├── .gitignore ├── README.md ├── app ├── composer.json └── index.php ├── appspec.yml ├── config ├── README.md ├── ansible_install.sh ├── ansible_run.sh ├── artisan_optimize.sh ├── clean_directory.sh ├── common_functions.sh ├── database_migrate.sh ├── deregister_from_elb.sh ├── register_with_elb.sh ├── site.yml ├── tasks │ ├── cloudwatch.yml │ ├── composer.yml │ ├── laravel.yml │ └── php.yml └── templates │ ├── awslogs.conf │ ├── htaccess │ └── laravel.conf ├── deploy ├── diagram.png ├── keys ├── bastion ├── bastion.pub ├── private └── private.pub ├── laravel ├── .env.example ├── .gitattributes ├── .gitignore ├── app │ ├── Console │ │ ├── Commands │ │ │ └── Inspire.php │ │ └── Kernel.php │ ├── Events │ │ └── Event.php │ ├── Exceptions │ │ └── Handler.php │ ├── Http │ │ ├── Controllers │ │ │ ├── Auth │ │ │ │ ├── AuthController.php │ │ │ │ └── PasswordController.php │ │ │ ├── Controller.php │ │ │ └── HomeController.php │ │ ├── Kernel.php │ │ ├── Middleware │ │ │ ├── Authenticate.php │ │ │ ├── EncryptCookies.php │ │ │ ├── RedirectIfAuthenticated.php │ │ │ └── VerifyCsrfToken.php │ │ ├── Requests │ │ │ └── Request.php │ │ └── routes.php │ ├── Jobs │ │ ├── Job.php │ │ └── TestQueue.php │ ├── Listeners │ │ └── .gitkeep │ ├── Policies │ │ └── .gitkeep │ ├── Providers │ │ ├── AppServiceProvider.php │ │ ├── AuthServiceProvider.php │ │ ├── EventServiceProvider.php │ │ └── RouteServiceProvider.php │ └── User.php ├── artisan ├── bootstrap │ ├── app.php │ ├── autoload.php │ └── cache │ │ └── .gitignore ├── composer.json ├── config │ ├── app.php │ ├── auth.php │ ├── broadcasting.php │ ├── cache.php │ ├── compile.php │ ├── database.php │ ├── filesystems.php │ ├── mail.php │ ├── queue.php │ ├── services.php │ ├── session.php │ └── view.php ├── database │ ├── .gitignore │ ├── factories │ │ └── ModelFactory.php │ ├── migrations │ │ ├── .gitkeep │ │ ├── 2014_10_12_000000_create_users_table.php │ │ └── 2014_10_12_100000_create_password_resets_table.php │ └── seeds │ │ ├── .gitkeep │ │ └── DatabaseSeeder.php ├── env ├── gulpfile.js ├── package.json ├── phpunit.xml ├── public │ ├── .htaccess │ ├── favicon.ico │ ├── index.php │ ├── robots.txt │ └── web.config ├── readme.md ├── resources │ ├── assets │ │ └── sass │ │ │ └── app.scss │ ├── lang │ │ └── en │ │ │ ├── auth.php │ │ │ ├── pagination.php │ │ │ ├── passwords.php │ │ │ └── validation.php │ └── views │ │ ├── auth │ │ ├── emails │ │ │ └── password.blade.php │ │ ├── login.blade.php │ │ ├── passwords │ │ │ ├── email.blade.php │ │ │ └── reset.blade.php │ │ └── register.blade.php │ │ ├── emails │ │ └── reminder.blade.php │ │ ├── errors │ │ └── 503.blade.php │ │ ├── home.blade.php │ │ ├── layouts │ │ └── app.blade.php │ │ ├── test.blade.php │ │ ├── vendor │ │ └── .gitkeep │ │ └── welcome.blade.php ├── server.php ├── storage │ ├── app │ │ ├── .gitignore │ │ └── public │ │ │ └── .gitignore │ ├── framework │ │ ├── .gitignore │ │ ├── cache │ │ │ └── .gitignore │ │ ├── sessions │ │ │ └── .gitignore │ │ └── views │ │ │ └── .gitignore │ └── logs │ │ └── .gitignore └── tests │ ├── ExampleTest.php │ └── TestCase.php ├── ssh.cfg.example ├── terraform ├── README.md ├── dns.tf ├── main.tf ├── modules │ ├── autoscaling │ │ ├── ec2-policy.json │ │ ├── ec2-role.json │ │ └── main.tf │ ├── codedeploy │ │ ├── codedeploy-policy.json │ │ ├── codedeploy-role.json │ │ └── main.tf │ ├── memcached │ │ └── main.tf │ └── network │ │ ├── bastion │ │ └── main.tf │ │ ├── dns.tf │ │ ├── nat │ │ └── main.tf │ │ ├── outputs.tf │ │ ├── subnet │ │ └── main.tf │ │ ├── subnets.tf │ │ ├── variables.tf │ │ ├── vpc.tf │ │ └── vpc │ │ └── main.tf ├── outputs.tf ├── scripts │ └── userdata.sh ├── security.tf ├── terraform.tfvars └── variables.tf └── watch /.gitignore: -------------------------------------------------------------------------------- 1 | # System Files 2 | .DS_Store 3 | 4 | # Terraform Files 5 | .terraform 6 | *.tfstate 7 | *.tfstate.backup 8 | 9 | # User Specific Files 10 | ssh.cfg 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AWS Terraform PHP Application 2 | 3 | ## Prerequisites 4 | 5 | - AWS account with administrative access 6 | - Route53 Domain (verified in SES for emails too) 7 | - [Terraform](http://terraform.io) 8 | 9 | ## Quickstart 10 | ```sh 11 | # deploy infrastructure 12 | cd terraform && terraform get 13 | terraform plan 14 | terraform apply 15 | 16 | # create bucket if it doesn't exist 17 | aws s3 mb s3://testapp.storage --region 18 | 19 | # update load balancer name in config/common_functions.sh 20 | 21 | # set deploy variables 22 | git config aws-codedeploy.application-name 23 | git config aws-codedeploy.s3bucket testapp.storage 24 | git config aws-codedeploy.deployment-group 25 | 26 | # update environment variables 27 | nano ./laravel/env 28 | 29 | # deploy code to instances 30 | ./deploy 31 | 32 | # check status of last deployment 33 | ./watch 34 | ``` 35 | 36 | ## What Does This Build? 37 | Here is a list of all pieces that this repo will put in place for a high availability 38 | Laravel application deployment and lifecycle. 39 | 40 | #### Infrastructure 41 | - virtual private cloud 42 | - public and private Subnets for each availability zone 43 | - nat gateways in each private subnet 44 | - bastion host in one public subnet 45 | - security groups 46 | - autoscaling group for web instances 47 | - elastic load balancer 48 | - internet gateway 49 | - routing tables 50 | - route53 domain setup 51 | - internal dns zone 52 | - ec2 userdata 53 | - rds mysql install with multi-az 54 | - elasticache memcached cluster 55 | - codedeploy application 56 | - codedeploy agent on ec2 instances 57 | - iam roles and policies 58 | - internal dns records 59 | - ssh keys 60 | 61 | #### Configuration 62 | On CodeDeploy, Ansible scripts will be run locally to configure each autoscaled machine. 63 | This will include this software. 64 | - apache webserver 65 | - php 5.6 66 | - cloudwatch log setup 67 | - aws-cli 68 | 69 | ## TODO 70 | 71 | - [X] Finish installing CloudTrail agent (http://docs.aws.amazon.com/AmazonCloudWatch/latest/DeveloperGuide/mon-scripts.html) 72 | - [X] ELB Register/Deregister : ASG Standby 73 | - [X] Add Elasticache Cluster 74 | - [X] S3/Laravel Filesystem Setup 75 | - [X] SQS/Laravel Queue Setup 76 | - [X] Send laravel.log to CloudTrail 77 | - [X] Memcached / Laravel Cache Test Endpoints 78 | - [X] Connect Laravel to SES 79 | - [ ] Add CloudFront 80 | - [ ] DNS Failover when instances are down 81 | - [ ] Set autoscaling policy to read memory 82 | - [ ] Add NACL to VPC 83 | - [ ] Add frontend build process to app (Gulp & NPM) 84 | - [ ] Build out app 85 | - [ ] Integration Tests / CodeDeploy Hooks 86 | - [ ] Make Ansible playbook more dynamic 87 | - [ ] Add [TrustedProxy?](https://github.com/fideloper/TrustedProxy) 88 | -------------------------------------------------------------------------------- /app/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "slalom/codedeploy", 3 | "license": "MIT", 4 | "require": { 5 | "php": ">=5.5.0", 6 | "aws/aws-sdk-php": "3.18.14" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /app/index.php: -------------------------------------------------------------------------------- 1 | 'latest', 9 | // 'region' => 'us-west-2' 10 | // ]); 11 | // 12 | // try { 13 | // $result = $s3->getObject([ 14 | // 'Bucket' => 'keyboardonfire.com', 15 | // 'Key' => 'images/ross.jpeg' 16 | // ]); 17 | // 18 | // echo '
';
19 | //     print_r($result);
20 | //     echo '
'; 21 | // } catch (Aws\Exception\S3Exception $e) { 22 | // echo "There was an error retrieving the file.\n"; 23 | // } 24 | 25 | $servername = "db.rossedman.internal"; 26 | $username = "admin"; 27 | $password = "password"; 28 | 29 | echo gethostname(); 30 | 31 | try { 32 | $conn = new PDO("mysql:host=$servername;dbname=basicapp", $username, $password); 33 | $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 34 | echo "Connected successfully"; 35 | } 36 | catch(PDOException $e) { 37 | echo "Connection failed: " . $e->getMessage(); 38 | } 39 | -------------------------------------------------------------------------------- /appspec.yml: -------------------------------------------------------------------------------- 1 | version: 0.0 2 | os: linux 3 | files: 4 | - source: ./laravel 5 | destination: /var/www/html 6 | - source: ./config 7 | destination: /tmp/config 8 | hooks: 9 | ApplicationStop: 10 | - location: config/deregister_from_elb.sh 11 | runas: root 12 | - location: config/clean_directory.sh 13 | runas: root 14 | BeforeInstall: 15 | - location: config/ansible_install.sh 16 | runas: root 17 | ApplicationStart: 18 | - location: config/ansible_run.sh 19 | runas: root 20 | - location: config/database_migrate.sh 21 | runas: ec2-user 22 | - location: config/artisan_optimize.sh 23 | runas: ec2-user 24 | - location: config/register_with_elb.sh 25 | runas: root 26 | -------------------------------------------------------------------------------- /config/README.md: -------------------------------------------------------------------------------- 1 | # AWS CodeDeploy Example 2 | This is a sample application and configuration to deploy through AWS CodeDeploy. 3 | This will configure a simple PHP server and deploy a few packages. 4 | 5 | ## Set Git Variables 6 | ``` 7 | git config aws-codedeploy.application-name TestApp 8 | git config aws-codedeploy.s3bucket development.merlin.lo 9 | git config aws-codedeploy.deployment-group AutoScalingWeb 10 | ``` 11 | -------------------------------------------------------------------------------- /config/ansible_install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Check for ansible tools, and attempt to install if not 4 | yum list installed python-pip &> /dev/null 5 | if [ $? != 0 ]; then 6 | yum install -y python-pip 7 | fi 8 | 9 | pip list | grep -q ansible 10 | if [ $? != 0 ]; then 11 | pip install ansible 12 | fi 13 | -------------------------------------------------------------------------------- /config/ansible_run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | /usr/local/bin/ansible-playbook /tmp/config/site.yml 3 | -------------------------------------------------------------------------------- /config/artisan_optimize.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | php /var/www/html/artisan optimize 3 | -------------------------------------------------------------------------------- /config/clean_directory.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | rm -rf /var/www/html /tmp/config 3 | -------------------------------------------------------------------------------- /config/common_functions.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"). 6 | # You may not use this file except in compliance with the License. 7 | # A copy of the License is located at 8 | # 9 | # http://aws.amazon.com/apache2.0 10 | # 11 | # or in the "license" file accompanying this file. This file is distributed 12 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | # express or implied. See the License for the specific language governing 14 | # permissions and limitations under the License. 15 | 16 | # ELB_LIST defines which Elastic Load Balancers this instance should be part of. 17 | # The elements in ELB_LIST should be seperated by space. 18 | ELB_LIST="tf-lb-vefmhrwijzaevazwrx5463lena" 19 | 20 | # Under normal circumstances, you shouldn't need to change anything below this line. 21 | # ----------------------------------------------------------------------------- 22 | 23 | export PATH="$PATH:/usr/bin:/usr/local/bin" 24 | 25 | # If true, all messages will be printed. If false, only fatal errors are printed. 26 | DEBUG=true 27 | 28 | # Number of times to check for a resouce to be in the desired state. 29 | WAITER_ATTEMPTS=60 30 | 31 | # Number of seconds to wait between attempts for resource to be in a state. 32 | WAITER_INTERVAL=1 33 | 34 | # AutoScaling Standby features at minimum require this version to work. 35 | MIN_CLI_VERSION='1.3.25' 36 | 37 | # Usage: get_instance_region 38 | # 39 | # Writes to STDOUT the AWS region as known by the local instance. 40 | get_instance_region() { 41 | if [ -z "$AWS_REGION" ]; then 42 | AWS_REGION=$(curl -s http://169.254.169.254/latest/dynamic/instance-identity/document \ 43 | | grep -i region \ 44 | | awk -F\" '{print $4}') 45 | fi 46 | 47 | echo $AWS_REGION 48 | } 49 | 50 | AWS_CLI="aws --region $(get_instance_region)" 51 | 52 | # Usage: autoscaling_group_name 53 | # 54 | # Prints to STDOUT the name of the AutoScaling group this instance is a part of and returns 0. If 55 | # it is not part of any groups, then it prints nothing. On error calling autoscaling, returns 56 | # non-zero. 57 | autoscaling_group_name() { 58 | local instance_id=$1 59 | 60 | # This operates under the assumption that instances are only ever part of a single ASG. 61 | local autoscaling_name=$($AWS_CLI autoscaling describe-auto-scaling-instances \ 62 | --instance-ids $instance_id \ 63 | --output text \ 64 | --query AutoScalingInstances[0].AutoScalingGroupName) 65 | 66 | if [ $? != 0 ]; then 67 | return 1 68 | elif [ "$autoscaling_name" == "None" ]; then 69 | echo "" 70 | else 71 | echo "${autoscaling_name}" 72 | fi 73 | 74 | return 0 75 | } 76 | 77 | # Usage: autoscaling_enter_standby 78 | # 79 | # Move into the Standby state in AutoScaling group . Doing so will 80 | # pull it out of any Elastic Load Balancer that might be in front of the group. 81 | # 82 | # Returns 0 if the instance was successfully moved to standby. Non-zero otherwise. 83 | autoscaling_enter_standby() { 84 | local instance_id=$1 85 | local asg_name=${2} 86 | 87 | msg "Checking if this instance has already been moved in the Standby state" 88 | local instance_state=$(get_instance_state_asg $instance_id) 89 | if [ $? != 0 ]; then 90 | msg "Unable to get this instance's lifecycle state." 91 | return 1 92 | fi 93 | 94 | if [ "$instance_state" == "Standby" ]; then 95 | msg "Instance is already in Standby; nothing to do." 96 | return 0 97 | fi 98 | 99 | if [ "$instance_state" == "Pending:Wait" ]; then 100 | msg "Instance is Pending:Wait; nothing to do." 101 | return 0 102 | fi 103 | 104 | msg "Checking to see if ASG ${asg_name} will let us decrease desired capacity" 105 | local min_desired=$($AWS_CLI autoscaling describe-auto-scaling-groups \ 106 | --auto-scaling-group-name "${asg_name}" \ 107 | --query 'AutoScalingGroups[0].[MinSize, DesiredCapacity]' \ 108 | --output text) 109 | 110 | local min_cap=$(echo $min_desired | awk '{print $1}') 111 | local desired_cap=$(echo $min_desired | awk '{print $2}') 112 | 113 | if [ -z "$min_cap" -o -z "$desired_cap" ]; then 114 | msg "Unable to determine minimum and desired capacity for ASG ${asg_name}." 115 | msg "Attempting to put this instance into standby regardless." 116 | elif [ $min_cap == $desired_cap -a $min_cap -gt 0 ]; then 117 | local new_min=$(($min_cap - 1)) 118 | msg "Decrementing ASG ${asg_name}'s minimum size to $new_min" 119 | msg $($AWS_CLI autoscaling update-auto-scaling-group \ 120 | --auto-scaling-group-name "${asg_name}" \ 121 | --min-size $new_min) 122 | if [ $? != 0 ]; then 123 | msg "Failed to reduce ASG ${asg_name}'s minimum size to $new_min. Cannot put this instance into Standby." 124 | return 1 125 | else 126 | msg "ASG ${asg_name}'s minimum size has been decremented, creating flag file /tmp/asgmindecremented" 127 | # Create a "flag" file to denote that the ASG min has been decremented 128 | touch /tmp/asgmindecremented 129 | fi 130 | fi 131 | 132 | msg "Putting instance $instance_id into Standby" 133 | $AWS_CLI autoscaling enter-standby \ 134 | --instance-ids $instance_id \ 135 | --auto-scaling-group-name "${asg_name}" \ 136 | --should-decrement-desired-capacity 137 | if [ $? != 0 ]; then 138 | msg "Failed to put instance $instance_id into Standby for ASG ${asg_name}." 139 | return 1 140 | fi 141 | 142 | msg "Waiting for move to Standby to finish" 143 | wait_for_state "autoscaling" $instance_id "Standby" 144 | if [ $? != 0 ]; then 145 | local wait_timeout=$(($WAITER_INTERVAL * $WAITER_ATTEMPTS)) 146 | msg "Instance $instance_id did not make it to standby after $wait_timeout seconds" 147 | return 1 148 | fi 149 | 150 | return 0 151 | } 152 | 153 | # Usage: autoscaling_exit_standby 154 | # 155 | # Attempts to move instance out of Standby and into InService. Returns 0 if 156 | # successful. 157 | autoscaling_exit_standby() { 158 | local instance_id=$1 159 | local asg_name=${2} 160 | 161 | msg "Checking if this instance has already been moved out of Standby state" 162 | local instance_state=$(get_instance_state_asg $instance_id) 163 | if [ $? != 0 ]; then 164 | msg "Unable to get this instance's lifecycle state." 165 | return 1 166 | fi 167 | 168 | if [ "$instance_state" == "InService" ]; then 169 | msg "Instance is already InService; nothing to do." 170 | return 0 171 | fi 172 | 173 | if [ "$instance_state" == "Pending:Wait" ]; then 174 | msg "Instance is Pending:Wait; nothing to do." 175 | return 0 176 | fi 177 | 178 | msg "Moving instance $instance_id out of Standby" 179 | $AWS_CLI autoscaling exit-standby \ 180 | --instance-ids $instance_id \ 181 | --auto-scaling-group-name "${asg_name}" 182 | if [ $? != 0 ]; then 183 | msg "Failed to put instance $instance_id back into InService for ASG ${asg_name}." 184 | return 1 185 | fi 186 | 187 | msg "Waiting for exit-standby to finish" 188 | wait_for_state "autoscaling" $instance_id "InService" 189 | if [ $? != 0 ]; then 190 | local wait_timeout=$(($WAITER_INTERVAL * $WAITER_ATTEMPTS)) 191 | msg "Instance $instance_id did not make it to InService after $wait_timeout seconds" 192 | return 1 193 | fi 194 | 195 | if [ -a /tmp/asgmindecremented ]; then 196 | local min_desired=$($AWS_CLI autoscaling describe-auto-scaling-groups \ 197 | --auto-scaling-group-name "${asg_name}" \ 198 | --query 'AutoScalingGroups[0].[MinSize, DesiredCapacity]' \ 199 | --output text) 200 | 201 | local min_cap=$(echo $min_desired | awk '{print $1}') 202 | 203 | local new_min=$(($min_cap + 1)) 204 | msg "Incrementing ASG ${asg_name}'s minimum size to $new_min" 205 | msg $($AWS_CLI autoscaling update-auto-scaling-group \ 206 | --auto-scaling-group-name "${asg_name}" \ 207 | --min-size $new_min) 208 | if [ $? != 0 ]; then 209 | msg "Failed to increase ASG ${asg_name}'s minimum size to $new_min." 210 | return 1 211 | else 212 | msg "Successfully incremented ASG ${asg_name}'s minimum size" 213 | msg "Removing /tmp/asgmindecremented flag file" 214 | rm -f /tmp/asgmindecremented 215 | fi 216 | else 217 | msg "Auto scaling group was not decremented previously, not incrementing min value" 218 | fi 219 | 220 | return 0 221 | } 222 | 223 | # Usage: get_instance_state_asg 224 | # 225 | # Gets the state of the given as known by the AutoScaling group it's a part of. 226 | # Health is printed to STDOUT and the function returns 0. Otherwise, no output and return is 227 | # non-zero. 228 | get_instance_state_asg() { 229 | local instance_id=$1 230 | 231 | local state=$($AWS_CLI autoscaling describe-auto-scaling-instances \ 232 | --instance-ids $instance_id \ 233 | --query "AutoScalingInstances[?InstanceId == \`$instance_id\`].LifecycleState | [0]" \ 234 | --output text) 235 | if [ $? != 0 ]; then 236 | return 1 237 | else 238 | echo $state 239 | return 0 240 | fi 241 | } 242 | 243 | reset_waiter_timeout() { 244 | local elb=$1 245 | local state_name=$2 246 | 247 | if [ "$state_name" == "InService" ]; then 248 | 249 | # Wait for a health check to succeed 250 | local timeout=$($AWS_CLI elb describe-load-balancers \ 251 | --load-balancer-name $elb \ 252 | --query 'LoadBalancerDescriptions[0].HealthCheck.Timeout') 253 | 254 | elif [ "$state_name" == "OutOfService" ]; then 255 | 256 | # If connection draining is enabled, wait for connections to drain 257 | local draining_values=$($AWS_CLI elb describe-load-balancer-attributes \ 258 | --load-balancer-name $elb \ 259 | --query 'LoadBalancerAttributes.ConnectionDraining.[Enabled,Timeout]' \ 260 | --output text) 261 | local draining_enabled=$(echo $draining_values | awk '{print $1}') 262 | local timeout=$(echo $draining_values | awk '{print $2}') 263 | 264 | if [ "$draining_enabled" != "True" ]; then 265 | timeout=0 266 | fi 267 | 268 | else 269 | msg "Unknown state name, '$state_name'"; 270 | return 1; 271 | fi 272 | 273 | # Base register/deregister action may take up to about 30 seconds 274 | timeout=$((timeout + 30)) 275 | 276 | WAITER_ATTEMPTS=$((timeout / WAITER_INTERVAL)) 277 | } 278 | 279 | # Usage: wait_for_state [ELB name] 280 | # 281 | # Waits for the state of to be in as seen by . Returns 0 if 282 | # it successfully made it to that state; non-zero if not. By default, checks $WAITER_ATTEMPTS 283 | # times, every $WAITER_INTERVAL seconds. If giving an [ELB name] to check under, these are reset 284 | # to that ELB's timeout values. 285 | wait_for_state() { 286 | local service=$1 287 | local instance_id=$2 288 | local state_name=$3 289 | local elb=$4 290 | 291 | local instance_state_cmd 292 | if [ "$service" == "elb" ]; then 293 | instance_state_cmd="get_instance_health_elb $instance_id $elb" 294 | reset_waiter_timeout $elb $state_name 295 | if [ $? != 0 ]; then 296 | error_exit "Failed resetting waiter timeout for $elb" 297 | fi 298 | elif [ "$service" == "autoscaling" ]; then 299 | instance_state_cmd="get_instance_state_asg $instance_id" 300 | else 301 | msg "Cannot wait for instance state; unknown service type, '$service'" 302 | return 1 303 | fi 304 | 305 | msg "Checking $WAITER_ATTEMPTS times, every $WAITER_INTERVAL seconds, for instance $instance_id to be in state $state_name" 306 | 307 | local instance_state=$($instance_state_cmd) 308 | local count=1 309 | 310 | msg "Instance is currently in state: $instance_state" 311 | while [ "$instance_state" != "$state_name" ]; do 312 | if [ $count -ge $WAITER_ATTEMPTS ]; then 313 | local timeout=$(($WAITER_ATTEMPTS * $WAITER_INTERVAL)) 314 | msg "Instance failed to reach state, $state_name within $timeout seconds" 315 | return 1 316 | fi 317 | 318 | sleep $WAITER_INTERVAL 319 | 320 | instance_state=$($instance_state_cmd) 321 | count=$(($count + 1)) 322 | msg "Instance is currently in state: $instance_state" 323 | done 324 | 325 | return 0 326 | } 327 | 328 | # Usage: get_instance_health_elb 329 | # 330 | # Gets the health of the given as known by . If it's a valid health 331 | # status (one of InService|OutOfService|Unknown), then the health is printed to STDOUT and the 332 | # function returns 0. Otherwise, no output and return is non-zero. 333 | get_instance_health_elb() { 334 | local instance_id=$1 335 | local elb_name=$2 336 | 337 | msg "Checking status of instance '$instance_id' in load balancer '$elb_name'" 338 | 339 | # If describe-instance-health for this instance returns an error, then it's not part of 340 | # this ELB. But, if the call was successful let's still double check that the status is 341 | # valid. 342 | local instance_status=$($AWS_CLI elb describe-instance-health \ 343 | --load-balancer-name $elb_name \ 344 | --instances $instance_id \ 345 | --query 'InstanceStates[].State' \ 346 | --output text 2>/dev/null) 347 | 348 | if [ $? == 0 ]; then 349 | case "$instance_status" in 350 | InService|OutOfService|Unknown) 351 | echo -n $instance_status 352 | return 0 353 | ;; 354 | *) 355 | msg "Instance '$instance_id' not part of ELB '$elb_name'" 356 | return 1 357 | esac 358 | fi 359 | } 360 | 361 | # Usage: validate_elb 362 | # 363 | # Validates that the Elastic Load Balancer with name exists, is describable, and 364 | # contains as one of its instances. 365 | # 366 | # If any of these checks are false, the function returns non-zero. 367 | validate_elb() { 368 | local instance_id=$1 369 | local elb_name=$2 370 | 371 | # Get the list of active instances for this LB. 372 | local elb_instances=$($AWS_CLI elb describe-load-balancers \ 373 | --load-balancer-name $elb_name \ 374 | --query 'LoadBalancerDescriptions[*].Instances[*].InstanceId' \ 375 | --output text) 376 | if [ $? != 0 ]; then 377 | msg "Couldn't describe ELB instance named '$elb_name'" 378 | return 1 379 | fi 380 | 381 | msg "Checking health of '$instance_id' as known by ELB '$elb_name'" 382 | local instance_health=$(get_instance_health_elb $instance_id $elb_name) 383 | if [ $? != 0 ]; then 384 | return 1 385 | fi 386 | 387 | return 0 388 | } 389 | 390 | # Usage: get_elb_list 391 | # 392 | # Finds all the ELBs that this instance is registered to. After execution, the variable 393 | # "ELB_LIST" will contain the list of load balancers for the given instance. 394 | # 395 | # If the given instance ID isn't found registered to any ELBs, the function returns non-zero 396 | get_elb_list() { 397 | local instance_id=$1 398 | 399 | local asg_name=$($AWS_CLI autoscaling describe-auto-scaling-instances \ 400 | --instance-ids $instance_id \ 401 | --query AutoScalingInstances[*].AutoScalingGroupName \ 402 | --output text | sed -e $'s/\t/ /g') 403 | local elb_list="" 404 | 405 | if [ -z "${asg_name}" ]; then 406 | msg "Instance is not part of an ASG. Looking up from ELB." 407 | local all_balancers=$($AWS_CLI elb describe-load-balancers \ 408 | --query LoadBalancerDescriptions[*].LoadBalancerName \ 409 | --output text | sed -e $'s/\t/ /g') 410 | for elb in $all_balancers; do 411 | local instance_health 412 | instance_health=$(get_instance_health_elb $instance_id $elb) 413 | if [ $? == 0 ]; then 414 | elb_list="$elb_list $elb" 415 | fi 416 | done 417 | else 418 | elb_list=$($AWS_CLI autoscaling describe-auto-scaling-groups \ 419 | --auto-scaling-group-names "${asg_name}" \ 420 | --query AutoScalingGroups[*].LoadBalancerNames \ 421 | --output text | sed -e $'s/\t/ /g') 422 | fi 423 | 424 | if [ -z "$elb_list" ]; then 425 | return 1 426 | else 427 | msg "Got load balancer list of: $elb_list" 428 | ELB_LIST=$elb_list 429 | return 0 430 | fi 431 | } 432 | 433 | # Usage: deregister_instance 434 | # 435 | # Deregisters from . 436 | deregister_instance() { 437 | local instance_id=$1 438 | local elb_name=$2 439 | 440 | $AWS_CLI elb deregister-instances-from-load-balancer \ 441 | --load-balancer-name $elb_name \ 442 | --instances $instance_id 1> /dev/null 443 | 444 | return $? 445 | } 446 | 447 | # Usage: register_instance 448 | # 449 | # Registers to . 450 | register_instance() { 451 | local instance_id=$1 452 | local elb_name=$2 453 | 454 | $AWS_CLI elb register-instances-with-load-balancer \ 455 | --load-balancer-name $elb_name \ 456 | --instances $instance_id 1> /dev/null 457 | 458 | return $? 459 | } 460 | 461 | # Usage: check_cli_version [version-to-check] [desired version] 462 | # 463 | # Without any arguments, checks that the installed version of the AWS CLI is at least at version 464 | # $MIN_CLI_VERSION. Returns non-zero if the version is not high enough. 465 | check_cli_version() { 466 | if [ -z $1 ]; then 467 | version=$($AWS_CLI --version 2>&1 | cut -f1 -d' ' | cut -f2 -d/) 468 | else 469 | version=$1 470 | fi 471 | 472 | if [ -z "$2" ]; then 473 | min_version=$MIN_CLI_VERSION 474 | else 475 | min_version=$2 476 | fi 477 | 478 | x=$(echo $version | cut -f1 -d.) 479 | y=$(echo $version | cut -f2 -d.) 480 | z=$(echo $version | cut -f3 -d.) 481 | 482 | min_x=$(echo $min_version | cut -f1 -d.) 483 | min_y=$(echo $min_version | cut -f2 -d.) 484 | min_z=$(echo $min_version | cut -f3 -d.) 485 | 486 | msg "Checking minimum required CLI version (${min_version}) against installed version ($version)" 487 | 488 | if [ $x -lt $min_x ]; then 489 | return 1 490 | elif [ $y -lt $min_y ]; then 491 | return 1 492 | elif [ $y -gt $min_y ]; then 493 | return 0 494 | elif [ $z -ge $min_z ]; then 495 | return 0 496 | else 497 | return 1 498 | fi 499 | } 500 | 501 | # Usage: msg 502 | # 503 | # Writes to STDERR only if $DEBUG is true, otherwise has no effect. 504 | msg() { 505 | local message=$1 506 | $DEBUG && echo $message 1>&2 507 | } 508 | 509 | # Usage: error_exit 510 | # 511 | # Writes to STDERR as a "fatal" and immediately exits the currently running script. 512 | error_exit() { 513 | local message=$1 514 | 515 | echo "[FATAL] $message" 1>&2 516 | exit 1 517 | } 518 | 519 | # Usage: get_instance_id 520 | # 521 | # Writes to STDOUT the EC2 instance ID for the local instance. Returns non-zero if the local 522 | # instance metadata URL is inaccessible. 523 | get_instance_id() { 524 | curl -s http://169.254.169.254/latest/meta-data/instance-id 525 | return $? 526 | } 527 | -------------------------------------------------------------------------------- /config/database_migrate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | php /var/www/html/artisan migrate 3 | -------------------------------------------------------------------------------- /config/deregister_from_elb.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"). 6 | # You may not use this file except in compliance with the License. 7 | # A copy of the License is located at 8 | # 9 | # http://aws.amazon.com/apache2.0 10 | # 11 | # or in the "license" file accompanying this file. This file is distributed 12 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | # express or implied. See the License for the specific language governing 14 | # permissions and limitations under the License. 15 | 16 | . $(dirname $0)/common_functions.sh 17 | 18 | msg "Running AWS CLI with region: $(get_instance_region)" 19 | 20 | # get this instance's ID 21 | INSTANCE_ID=$(get_instance_id) 22 | if [ $? != 0 -o -z "$INSTANCE_ID" ]; then 23 | error_exit "Unable to get this instance's ID; cannot continue." 24 | fi 25 | 26 | # Get current time 27 | msg "Started $(basename $0) at $(/bin/date "+%F %T")" 28 | start_sec=$(/bin/date +%s.%N) 29 | 30 | msg "Checking if instance $INSTANCE_ID is part of an AutoScaling group" 31 | asg=$(autoscaling_group_name $INSTANCE_ID) 32 | if [ $? == 0 -a -n "${asg}" ]; then 33 | msg "Found AutoScaling group for instance $INSTANCE_ID: ${asg}" 34 | 35 | msg "Checking that installed CLI version is at least at version required for AutoScaling Standby" 36 | check_cli_version 37 | if [ $? != 0 ]; then 38 | error_exit "CLI must be at least version ${MIN_CLI_X}.${MIN_CLI_Y}.${MIN_CLI_Z} to work with AutoScaling Standby" 39 | fi 40 | 41 | msg "Attempting to put instance into Standby" 42 | autoscaling_enter_standby $INSTANCE_ID "${asg}" 43 | if [ $? != 0 ]; then 44 | error_exit "Failed to move instance into standby" 45 | else 46 | msg "Instance is in standby" 47 | exit 0 48 | fi 49 | fi 50 | 51 | msg "Instance is not part of an ASG, continuing..." 52 | 53 | msg "Checking that user set at least one load balancer" 54 | if test -z "$ELB_LIST"; then 55 | error_exit "Must have at least one load balancer to deregister from" 56 | fi 57 | 58 | # Loop through all LBs the user set, and attempt to deregister this instance from them. 59 | for elb in $ELB_LIST; do 60 | msg "Checking validity of load balancer named '$elb'" 61 | validate_elb $INSTANCE_ID $elb 62 | if [ $? != 0 ]; then 63 | msg "Error validating $elb; cannot continue with this LB" 64 | continue 65 | fi 66 | 67 | msg "Deregistering $INSTANCE_ID from $elb" 68 | deregister_instance $INSTANCE_ID $elb 69 | 70 | if [ $? != 0 ]; then 71 | error_exit "Failed to deregister instance $INSTANCE_ID from ELB $elb" 72 | fi 73 | done 74 | 75 | # Wait for all Deregistrations to finish 76 | msg "Waiting for instance to de-register from its load balancers" 77 | for elb in $ELB_LIST; do 78 | wait_for_state "elb" $INSTANCE_ID "OutOfService" $elb 79 | if [ $? != 0 ]; then 80 | error_exit "Failed waiting for $INSTANCE_ID to leave $elb" 81 | fi 82 | done 83 | 84 | msg "Finished $(basename $0) at $(/bin/date "+%F %T")" 85 | 86 | end_sec=$(/bin/date +%s.%N) 87 | elapsed_seconds=$(echo "$end_sec - $start_sec" | /usr/bin/bc) 88 | 89 | msg "Elapsed time: $elapsed_seconds" 90 | -------------------------------------------------------------------------------- /config/register_with_elb.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"). 6 | # You may not use this file except in compliance with the License. 7 | # A copy of the License is located at 8 | # 9 | # http://aws.amazon.com/apache2.0 10 | # 11 | # or in the "license" file accompanying this file. This file is distributed 12 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | # express or implied. See the License for the specific language governing 14 | # permissions and limitations under the License. 15 | 16 | . $(dirname $0)/common_functions.sh 17 | 18 | msg "Running AWS CLI with region: $(get_instance_region)" 19 | 20 | # get this instance's ID 21 | INSTANCE_ID=$(get_instance_id) 22 | if [ $? != 0 -o -z "$INSTANCE_ID" ]; then 23 | error_exit "Unable to get this instance's ID; cannot continue." 24 | fi 25 | 26 | # Get current time 27 | msg "Started $(basename $0) at $(/bin/date "+%F %T")" 28 | start_sec=$(/bin/date +%s.%N) 29 | 30 | msg "Checking if instance $INSTANCE_ID is part of an AutoScaling group" 31 | asg=$(autoscaling_group_name $INSTANCE_ID) 32 | if [ $? == 0 -a -n "${asg}" ]; then 33 | msg "Found AutoScaling group for instance $INSTANCE_ID: ${asg}" 34 | 35 | msg "Checking that installed CLI version is at least at version required for AutoScaling Standby" 36 | check_cli_version 37 | if [ $? != 0 ]; then 38 | error_exit "CLI must be at least version ${MIN_CLI_X}.${MIN_CLI_Y}.${MIN_CLI_Z} to work with AutoScaling Standby" 39 | fi 40 | 41 | msg "Attempting to move instance out of Standby" 42 | autoscaling_exit_standby $INSTANCE_ID "${asg}" 43 | if [ $? != 0 ]; then 44 | error_exit "Failed to move instance out of standby" 45 | else 46 | msg "Instance is no longer in Standby" 47 | exit 0 48 | fi 49 | fi 50 | 51 | msg "Instance is not part of an ASG, continuing..." 52 | 53 | msg "Checking that user set at least one load balancer" 54 | if test -z "$ELB_LIST"; then 55 | error_exit "Must have at least one load balancer to register to" 56 | fi 57 | 58 | # Loop through all LBs the user set, and attempt to register this instance to them. 59 | for elb in $ELB_LIST; do 60 | msg "Checking validity of load balancer named '$elb'" 61 | validate_elb $INSTANCE_ID $elb 62 | if [ $? != 0 ]; then 63 | msg "Error validating $elb; cannot continue with this LB" 64 | continue 65 | fi 66 | 67 | msg "Registering $INSTANCE_ID to $elb" 68 | register_instance $INSTANCE_ID $elb 69 | 70 | if [ $? != 0 ]; then 71 | error_exit "Failed to register instance $INSTANCE_ID from ELB $elb" 72 | fi 73 | done 74 | 75 | # Wait for all Registrations to finish 76 | msg "Waiting for instance to register to its load balancers" 77 | for elb in $ELB_LIST; do 78 | wait_for_state "elb" $INSTANCE_ID "InService" $elb 79 | if [ $? != 0 ]; then 80 | error_exit "Failed waiting for $INSTANCE_ID to return to $elb" 81 | fi 82 | done 83 | 84 | msg "Finished $(basename $0) at $(/bin/date "+%F %T")" 85 | 86 | end_sec=$(/bin/date +%s.%N) 87 | elapsed_seconds=$(echo "$end_sec - $start_sec" | /usr/bin/bc) 88 | 89 | msg "Elapsed time: $elapsed_seconds" 90 | -------------------------------------------------------------------------------- /config/site.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: 127.0.0.1 3 | connection: local 4 | become: yes 5 | vars: 6 | aws_region: us-west-2 7 | tasks: 8 | - name: install php/apache 9 | include: tasks/php.yml 10 | 11 | - name: install composer 12 | include: tasks/composer.yml 13 | 14 | - name: install cloudwatch agent 15 | include: tasks/cloudwatch.yml 16 | 17 | - name: set permissions for deployment 18 | file: path=/var/www owner=ec2-user group=apache mode=0755 recurse=yes 19 | 20 | - name: setup laravel deployment 21 | include: tasks/laravel.yml 22 | 23 | - name: install composer packages 24 | composer: command=install working_dir=/var/www/html 25 | become_user: ec2-user 26 | 27 | - name: restart apache 28 | service: name=httpd state=restarted 29 | -------------------------------------------------------------------------------- /config/tasks/cloudwatch.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: install cloudwatch logs agent 3 | yum: name=awslogs 4 | 5 | - name: add region to config 6 | lineinfile: 7 | dest: /etc/awslogs/awscli.conf 8 | regexp: ^region 9 | line: region = {{ aws_region }} 10 | 11 | - name: configure cloudwatch logs 12 | template: src=/tmp/config/templates/awslogs.conf dest=/etc/awslogs/awslogs.conf 13 | 14 | - name: start cloudwatch agent 15 | service: name=awslogs state=restarted enabled=true 16 | -------------------------------------------------------------------------------- /config/tasks/composer.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: download composer installer 3 | get_url: 4 | url: https://getcomposer.org/installer 5 | dest: /tmp/composer-installer.php 6 | mode: 0755 7 | 8 | - name: run composer installer 9 | command: > 10 | php composer-installer.php 11 | chdir=/tmp 12 | 13 | - name: make composer global 14 | shell: > 15 | mv /tmp/composer.phar /usr/local/bin/composer 16 | creates=/usr/local/bin/composer 17 | -------------------------------------------------------------------------------- /config/tasks/laravel.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # - name: change apache document root 3 | # lineinfile: dest=/etc/httpd/conf/httpd.conf regexp='^DocumentRoot "/var/www/html"' line='DocumentRoot "/var/www/html/public"' 4 | 5 | - name: ensure laravel directories exists 6 | file: path={{item}} state=directory recurse=yes mode=0777 owner=ec2-user group=apache 7 | with_items: 8 | - /var/www/html/bootstrap/cache 9 | - /var/www/html/storage/logs 10 | - /var/www/html/storage/app/public 11 | - /var/www/html/storage/framework/cache 12 | - /var/www/html/storage/framework/sessions 13 | - /var/www/html/storage/framework/views 14 | 15 | - name: ensure laravel log exists 16 | file: path=/var/www/html/storage/logs/laravel.log state=touch mode=0777 17 | 18 | - name: copy env file 19 | copy: src=/var/www/html/env dest=/var/www/html/.env remote_src=true owner=apache group=apache 20 | 21 | - name: copy apache conf file 22 | template: src=templates/laravel.conf dest=/etc/httpd/conf.d/vhosts.conf 23 | 24 | - name: copy htaccess file 25 | template: src=templates/htaccess dest=/var/www/html/public/.htaccess 26 | -------------------------------------------------------------------------------- /config/tasks/php.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: install php 3 | yum: name={{ item }} 4 | with_items: 5 | - httpd24 6 | - php56 7 | - php56-common 8 | - php56-devel 9 | - php56-cli 10 | - php56-mbstring 11 | - php56-mcrypt 12 | - php56-pdo 13 | - php56-mysqlnd 14 | - php56-pecl-memcached 15 | 16 | - name: configure php 17 | lineinfile: dest=/etc/php.ini regexp="^date.timezone" line="date.timezone = America/Chicago" 18 | 19 | - name: add ec2-user to apache group 20 | user: name=ec2-user groups=apache append=yes 21 | 22 | - name: restart apache 23 | service: name=httpd state=started 24 | -------------------------------------------------------------------------------- /config/templates/awslogs.conf: -------------------------------------------------------------------------------- 1 | [/var/log/messages] 2 | datetime_format = %b %d %H:%M:%S 3 | file = /var/log/messages 4 | buffer_duration = 5000 5 | log_stream_name = {instance_id} 6 | initial_position = start_of_file 7 | log_group_name = /var/log/messages 8 | 9 | [/var/log/httpd/error_log] 10 | datetime_format = %b %d %H:%M:%S 11 | file = /var/log/httpd/error_log 12 | buffer_duration = 5000 13 | log_stream_name = {instance_id} 14 | initial_position = start_of_file 15 | log_group_name = /var/log/httpd/error_log 16 | 17 | [/var/log/httpd/access_log] 18 | datetime_format = %b %d %H:%M:%S 19 | file = /var/log/httpd/access_log 20 | buffer_duration = 5000 21 | log_stream_name = {instance_id} 22 | initial_position = start_of_file 23 | log_group_name = /var/log/httpd/access_log 24 | 25 | [/var/www/html/storage/logs/laravel.log] 26 | datetime_format = %b %d %H:%M:%S 27 | file = /var/www/html/storage/logs/laravel.log 28 | buffer_duration = 5000 29 | log_stream_name = {instance_id} 30 | initial_position = start_of_file 31 | log_group_name = /var/www/html/storage/logs/laravel.log 32 | -------------------------------------------------------------------------------- /config/templates/htaccess: -------------------------------------------------------------------------------- 1 | 2 | 3 | Options -MultiViews 4 | 5 | 6 | RewriteEngine On 7 | 8 | # Redirect Trailing Slashes If Not A Folder... 9 | RewriteCond %{REQUEST_FILENAME} !-d 10 | RewriteRule ^(.*)/$ /$1 [L,R=301] 11 | 12 | # Handle Front Controller... 13 | RewriteCond %{REQUEST_FILENAME} !-d 14 | RewriteCond %{REQUEST_FILENAME} !-f 15 | RewriteRule ^ index.php [L] 16 | 17 | # Handle Authorization Header 18 | RewriteCond %{HTTP:Authorization} . 19 | RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] 20 | 21 | -------------------------------------------------------------------------------- /config/templates/laravel.conf: -------------------------------------------------------------------------------- 1 | 2 | ServerName rossedman.me 3 | DocumentRoot "/var/www/html/public" 4 | 5 | AllowOverride all 6 | Order allow,deny 7 | allow from all 8 | 9 | 10 | -------------------------------------------------------------------------------- /deploy: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"). 6 | # You may not use this file except in compliance with the License. 7 | # A copy of the License is located at 8 | # 9 | # http://aws.amazon.com/apache2.0 10 | # 11 | # or in the "license" file accompanying this file. This file is distributed 12 | # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | # express or implied. See the License for the specific language governing 14 | # permissions and limitations under the License. 15 | 16 | AWS="/usr/local/bin/aws" 17 | 18 | APPLICATION_NAME=$(git config --get aws-codedeploy.application-name) 19 | DEPLOYMENT_GROUP=$(git config --get aws-codedeploy.deployment-group) 20 | BUCKET_NAME=$(git config --get aws-codedeploy.s3bucket) 21 | BUNDLE_NAME=$(echo $(basename `pwd`).zip) 22 | 23 | # `aws deploy push` will overwrite the bundle in S3. If you'd rather ensure that you have a unique 24 | # object for each push, you could, for example, append the commit hash: 25 | BUNDLE_NAME=$(echo $(basename `pwd`)-$(git log -n 1 --format=%H).zip) 26 | 27 | # Call `aws deploy push` to create a new revision of the current repo 28 | echo "Pushing $BUNDLE_NAME to s3://${BUCKET_NAME} and registering with application '${APPLICATION_NAME}'" 1>&2 29 | $AWS deploy push \ 30 | --application-name ${APPLICATION_NAME} \ 31 | --s3-location s3://${BUCKET_NAME}/${BUNDLE_NAME} \ 32 | --ignore-hidden-files \ 33 | --source . 34 | 35 | revision_json="{\"revisionType\":\"S3\",\"s3Location\":{\"bucket\":\"${BUCKET_NAME}\",\"bundleType\":\"zip\",\"key\":\"${BUNDLE_NAME}\"}}" 36 | 37 | if [ $? != 0 ]; then 38 | echo "Push to codedeploy failed; skipping create-deployment" 1>&2 39 | else 40 | echo "Deploying s3://${BUCKET_NAME}/${BUNDLE_NAME} to application ${APPLICATION_NAME} and deployment group ${DEPLOYMENT_GROUP}" 1>&2 41 | $AWS deploy create-deployment \ 42 | --application-name ${APPLICATION_NAME} \ 43 | --deployment-group-name ${DEPLOYMENT_GROUP} \ 44 | --revision $revision_json 45 | fi 46 | -------------------------------------------------------------------------------- /diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rossedman/aws-terraform-laravel/9794648ee2f70bef3145166cbcbdd1db163c0f51/diagram.png -------------------------------------------------------------------------------- /keys/bastion: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEA0aToEJ8MaLfbpXHxbn1b+3KvkOvgelQ0jqmTO39UV2bGzTjM 3 | 9KnVbL6bQhohlaOxp+FClmrs0CohvwcJ0lIvFDOTGNqkEjhFWGASQbVBC/i3dXsu 4 | RvOrGGL9n8VIh8/4TLe4MDXhGlpzyswd3yFt3OpGAkISyaq3sxbIoQKHvXPXrCrE 5 | c65DvAiYU4R4tnahsjVTXF2zgB18anHvPxwAyGl4mlSx5LzWlm9mV49kuYWxiI31 6 | biHrK7AqQP1XykN+GBVf7zqZTr27hKLdXzI6jYi+EUE1jsMRnqwRGFtE+/hSkWQl 7 | ZptqtLC4dcCQq3/EhQZfhP1HE5F2JufDPpEv2wIDAQABAoIBAC17Q0Vn2/9T8/j+ 8 | sUwxMiVpCiG8qqSfZA+XRnPf+eJET9jx+7UQq1a+O1yp4qNeMgqj2hhb9ihrG4sf 9 | 8ceJQOF3FvCLbpDtWE4F+a/7rLL2MIbyRGXsMzBFOZTR7hxYyBuMuA7tgXqAKSLU 10 | CZ8A157XzHxs7TqHKPdXeAtGS0CUXpwubo2zJHNHqKDAooYLp+AckoNBQNF6hRMB 11 | bNYoQK7gw8oMp/G/W+fwc2SNvsnPuZzjZMUPARqEsUPZqrtFrnnKEYFRl5IFInLI 12 | C0zj/pERhIjF2r0lzPIJEn+RPcnS2oqRQHpoaHolVVeST5dL9iYMeHBuvYDgDS8k 13 | mCnoWeECgYEA8KyoU8TEuMO0ad8GDW3tQR72GF73fyOxyR9dSf9gKJmvLSd1SfpS 14 | VpVNbc7THWULgRvkRcOjFApwqimE0TiDm/0y2T23UU42xPcQR/BtPMWJKv07POOF 15 | 0w9IBc9Ed2prOXh4OwxSSo9C86/2sRgQs+2PYQQlq0ldynDnEHr1RVMCgYEA3v5p 16 | E04e+uI3X+PslrxqcgtoF2Ddb0Lmqrs1fXb0XbnPmd2HQHoKCJsJNR89WlDLgvxm 17 | PoxbzI0jxqmxhSXj3MjzZFBxumEF7ajujbWmt1NACnLL5RjYl8L1MY2oelQkMTwk 18 | yyM1l4L865yidOtYEGAa8Sm/RDgBppynunYa0lkCgYAPeLn1cJ/I1OPjLnAgKuHm 19 | nsvpMymr5aqHKFoB6MXQtlh5iaDTmaDzafOpTHNr31QG/7kD9xijsCwf9D1SidSE 20 | EZnUN1ByjJmevdcxGLadAoHX3qGRP3sZ31Cc9v8Kwi+UaTcpbJhZrK38JmKwbcCd 21 | IHdoIDEfur6pxepEt/LOewKBgBeK1n8SRVUJYv09q/GyDK7jo2asdFRVxNKLlzca 22 | wuvOPSuqZqgY+kw0SgGQvcJ2OzYl/Ylm+h4bXIaRzcsX1/msQX36vDcIHT8dEapm 23 | XiaGpIE1427Zc6x6CbbklL/teDC2f8/udK79RkR9se0UF6UK8G07khTasNntOgwG 24 | gghpAoGBAI7Gio/tbiA7m91FoMbppxUVW0TmTpzhM/NdSHiVRVyF3EkcK1Ism+ZC 25 | HaN9A3nCj8fKy9za1E1yp/NC1V5Qkj8uKqZ5gZwHQQdAzRQQg2N/OeD8jwN+BDMC 26 | v/ujSAj/prMhvKJpTVHq595Z7kSimelz37ndbOil16kXbSMnKwke 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /keys/bastion.pub: -------------------------------------------------------------------------------- 1 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDRpOgQnwxot9ulcfFufVv7cq+Q6+B6VDSOqZM7f1RXZsbNOMz0qdVsvptCGiGVo7Gn4UKWauzQKiG/BwnSUi8UM5MY2qQSOEVYYBJBtUEL+Ld1ey5G86sYYv2fxUiHz/hMt7gwNeEaWnPKzB3fIW3c6kYCQhLJqrezFsihAoe9c9esKsRzrkO8CJhThHi2dqGyNVNcXbOAHXxqce8/HADIaXiaVLHkvNaWb2ZXj2S5hbGIjfVuIesrsCpA/VfKQ34YFV/vOplOvbuEot1fMjqNiL4RQTWOwxGerBEYW0T7+FKRZCVmm2q0sLh1wJCrf8SFBl+E/UcTkXYm58M+kS/b ross.edman@28355-MBPR.local 2 | -------------------------------------------------------------------------------- /keys/private: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpQIBAAKCAQEAuwKflmKYsHspC5lPZ49VrCzA2RgMIwrIdgAc2jk4o8MlT8yy 3 | qDBhH5IaS3VqqqI5bRGpmNKKKPIxwEGkim7XS4v3RmfxcGtk8rDaG2GZt3sMXBhS 4 | yvr6t2yvhjXotumulkpLIFgEcxpmOMBKGaMBY3rPg3WyfRrBE+K0Xwt0gTaQeVPz 5 | dD6ubsvtTn9uBpoJ6IHAwgFLDlL/HHin5mISAUndvZiHcSgReH2tN/5U3WkH9eNM 6 | PbQGwvazU56BokGZgx2RvDfuzBZ9zK85xqJ1ZrknogmEEB/n7QFW28OdYb5vHTyN 7 | hC9F+8BvWysPJktvjUd1pt2u/wT84mN1e3fE3QIDAQABAoIBAQCSLTPHHhyR3kMw 8 | IM8TeNOTuIupZgWeooAc1Gu5G/8s6o3QuYVwuBhC0DYjg400AYf3vFWf8foylVXU 9 | HLtbxdYd5DMN4pOztw56MUjbHEhGRjVcC1sz9Ehjdd4hfyP/Tdu8+CePCZ24xwre 10 | E1gYf/TG6Kkp7abt6SrAu3UX0eFoWYM2vvd2wCm8EYIeyievxiRVWv/N8mJCaWQV 11 | 134uhZ08V9F8eXp6eqNkXK/1AysCGBoo3Rw6ZxBN9CAbmgiUf0L4sLxOEqZFq8jd 12 | SjpMKOh2+ccu1iikMxNcpr0lm/YXbAO2gNQuf6P3zrlfaKWrnAKwc3OYNZFeK98J 13 | g9+mjHhBAoGBANuQ5yfUdJvzZUn4EKNJN7ep805b0NvMfE7r6REECGpR1M981ffE 14 | sjkid1tfoJ3FLzOjaGwZf5n/RRaFDdeClIWYvh5JdjlB+otaYE0UgXl5vxxjisyr 15 | zjYU1eZhJSMoLziF6aTL+JOvrHuFL/qdDxYfH1tDfEhpPbw0z/M2Z1MNAoGBANoK 16 | ws8aj7xL3BrrBy3guzV3kJCg5bU9xcPCGevb+sa5ZtgR8JtwC+56twZhqHXwC+mO 17 | YIYkLaenPdz+ka7fornVUL+t1KwjScFWSFmhpYGOSROSWBRQ6m+0pd2mUMKKL7aC 18 | 1PtnMTjWyAWJLmH9K9OZO7UfkL90WtGcE2zy7AURAoGBAJkiOtXgq2OJIf+w74my 19 | qxWBhpwEFWr290vj5S1k7qmYYSBFJMYlfVez3iLwUwk2WXFeapnaPtCc5QaLzdec 20 | zxFOMmrVOYs9pQxEAB5CSvr6GnwmQMv2l1/IsFZ5MnmOsUBuxUGWsMvwHhAYGBpm 21 | J/t5wVjZfHjUTaZR/ybVrsKRAoGBAL9lYsvZTQLEtFkMpiindK3iXowWMI1/w/Gq 22 | mIZpeyCl7pkMZmCLYm3cWnzHjNC5/jruN9yINWtNawhqjgcrV/Q4Q8F+HYldEIkd 23 | 7DSBqH6pH4yGkbqDrMaRlGeUbp/WHTvgbISieJqkLsBtQsHRMn9zqu2635yvzmjg 24 | 0Ex6kKOBAoGAL2R/eRONUk68n+IJVAroZqhyDwhvJVDvtQcbr+kY0emFlq7xU30E 25 | 34QTvpECD3xD9WENPd1xizVFBQk4wcGns0BF77AqqIys7GZjRHq8GqF6+4jP2kqw 26 | FDHGgXfCcCRIoZJ3HEiuyJTWy0D3j+GuQbWOAe2Aoy/NwYtxNMzIu90= 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /keys/private.pub: -------------------------------------------------------------------------------- 1 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Ap+WYpiweykLmU9nj1WsLMDZGAwjCsh2ABzaOTijwyVPzLKoMGEfkhpLdWqqojltEamY0ooo8jHAQaSKbtdLi/dGZ/Fwa2TysNobYZm3ewxcGFLK+vq3bK+GNei26a6WSksgWARzGmY4wEoZowFjes+DdbJ9GsET4rRfC3SBNpB5U/N0Pq5uy+1Of24GmgnogcDCAUsOUv8ceKfmYhIBSd29mIdxKBF4fa03/lTdaQf140w9tAbC9rNTnoGiQZmDHZG8N+7MFn3MrznGonVmuSeiCYQQH+ftAVbbw51hvm8dPI2EL0X7wG9bKw8mS2+NR3Wm3a7/BPziY3V7d8Td ross.edman@28355-MBPR.local 2 | -------------------------------------------------------------------------------- /laravel/.env.example: -------------------------------------------------------------------------------- 1 | APP_ENV=local 2 | APP_DEBUG=true 3 | APP_KEY=SomeRandomString 4 | APP_URL=http://localhost 5 | 6 | DB_CONNECTION=mysql 7 | DB_HOST=127.0.0.1 8 | DB_PORT=3306 9 | DB_DATABASE=homestead 10 | DB_USERNAME=homestead 11 | DB_PASSWORD=secret 12 | 13 | CACHE_DRIVER=file 14 | SESSION_DRIVER=file 15 | QUEUE_DRIVER=sync 16 | 17 | REDIS_HOST=127.0.0.1 18 | REDIS_PASSWORD=null 19 | REDIS_PORT=6379 20 | 21 | MAIL_DRIVER=smtp 22 | MAIL_HOST=mailtrap.io 23 | MAIL_PORT=2525 24 | MAIL_USERNAME=null 25 | MAIL_PASSWORD=null 26 | MAIL_ENCRYPTION=null 27 | -------------------------------------------------------------------------------- /laravel/.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.css linguist-vendored 3 | *.scss linguist-vendored 4 | -------------------------------------------------------------------------------- /laravel/.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | /node_modules 3 | /public/storage 4 | Homestead.yaml 5 | Homestead.json 6 | .env 7 | -------------------------------------------------------------------------------- /laravel/app/Console/Commands/Inspire.php: -------------------------------------------------------------------------------- 1 | comment(PHP_EOL.Inspiring::quote().PHP_EOL); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /laravel/app/Console/Kernel.php: -------------------------------------------------------------------------------- 1 | command('inspire') 28 | // ->hourly(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /laravel/app/Events/Event.php: -------------------------------------------------------------------------------- 1 | middleware($this->guestMiddleware(), ['except' => 'logout']); 41 | } 42 | 43 | /** 44 | * Get a validator for an incoming registration request. 45 | * 46 | * @param array $data 47 | * @return \Illuminate\Contracts\Validation\Validator 48 | */ 49 | protected function validator(array $data) 50 | { 51 | return Validator::make($data, [ 52 | 'name' => 'required|max:255', 53 | 'email' => 'required|email|max:255|unique:users', 54 | 'password' => 'required|min:6|confirmed', 55 | ]); 56 | } 57 | 58 | /** 59 | * Create a new user instance after a valid registration. 60 | * 61 | * @param array $data 62 | * @return User 63 | */ 64 | protected function create(array $data) 65 | { 66 | return User::create([ 67 | 'name' => $data['name'], 68 | 'email' => $data['email'], 69 | 'password' => bcrypt($data['password']), 70 | ]); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /laravel/app/Http/Controllers/Auth/PasswordController.php: -------------------------------------------------------------------------------- 1 | middleware($this->guestMiddleware()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /laravel/app/Http/Controllers/Controller.php: -------------------------------------------------------------------------------- 1 | middleware('auth'); 18 | } 19 | 20 | /** 21 | * Show the application dashboard. 22 | * 23 | * @return \Illuminate\Http\Response 24 | */ 25 | public function index() 26 | { 27 | return view('home'); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /laravel/app/Http/Kernel.php: -------------------------------------------------------------------------------- 1 | [ 27 | \App\Http\Middleware\EncryptCookies::class, 28 | \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, 29 | \Illuminate\Session\Middleware\StartSession::class, 30 | \Illuminate\View\Middleware\ShareErrorsFromSession::class, 31 | \App\Http\Middleware\VerifyCsrfToken::class, 32 | ], 33 | 34 | 'api' => [ 35 | 'throttle:60,1', 36 | ], 37 | ]; 38 | 39 | /** 40 | * The application's route middleware. 41 | * 42 | * These middleware may be assigned to groups or used individually. 43 | * 44 | * @var array 45 | */ 46 | protected $routeMiddleware = [ 47 | 'auth' => \App\Http\Middleware\Authenticate::class, 48 | 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, 49 | 'can' => \Illuminate\Foundation\Http\Middleware\Authorize::class, 50 | 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, 51 | 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, 52 | ]; 53 | } 54 | -------------------------------------------------------------------------------- /laravel/app/Http/Middleware/Authenticate.php: -------------------------------------------------------------------------------- 1 | guest()) { 21 | if ($request->ajax() || $request->wantsJson()) { 22 | return response('Unauthorized.', 401); 23 | } else { 24 | return redirect()->guest('login'); 25 | } 26 | } 27 | 28 | return $next($request); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /laravel/app/Http/Middleware/EncryptCookies.php: -------------------------------------------------------------------------------- 1 | check()) { 21 | return redirect('/'); 22 | } 23 | 24 | return $next($request); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /laravel/app/Http/Middleware/VerifyCsrfToken.php: -------------------------------------------------------------------------------- 1 | get('test_key'); 26 | }); 27 | 28 | Route::get('cache/set', function (Cache $cache) { 29 | return $cache->put('test_key', 'value', 10); 30 | }); 31 | 32 | Route::get('user/create', function (User $user) { 33 | return $user->create([ 34 | 'name' => 'Ross Edman', 35 | 'email' => 'ross.edman@slalom.com', 36 | 'password' => 'password' 37 | ]); 38 | }); 39 | 40 | Route::get('user/get', function (User $user) { 41 | return $user->all(); 42 | }); 43 | 44 | Route::get('session/store', function() { 45 | return session(['test' => 'session']); 46 | }); 47 | 48 | Route::get('session/get', function() { 49 | return session('test'); 50 | }); 51 | 52 | Route::get('filesystem/test', function() { 53 | return Storage::disk('s3')->files('/'); 54 | }); 55 | 56 | Route::get('jobs/test', function (User $user) { 57 | return dispatch(new App\Jobs\TestQueue($user)); 58 | }); 59 | 60 | Route::get('email/test', function () { 61 | return Mail::send('emails.reminder', [], function ($m) { 62 | $m->from('admin@rossedman.me', 'Your Application'); 63 | $m->to('ross.edman@slalom.com', 'Ross Edman')->subject('Your Reminder!'); 64 | }); 65 | }); 66 | -------------------------------------------------------------------------------- /laravel/app/Jobs/Job.php: -------------------------------------------------------------------------------- 1 | user = $user; 25 | } 26 | 27 | /** 28 | * Execute the job. 29 | * 30 | * @return void 31 | */ 32 | public function handle() 33 | { 34 | return $this->user->all(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /laravel/app/Listeners/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /laravel/app/Policies/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /laravel/app/Providers/AppServiceProvider.php: -------------------------------------------------------------------------------- 1 | 'App\Policies\ModelPolicy', 17 | ]; 18 | 19 | /** 20 | * Register any application authentication / authorization services. 21 | * 22 | * @param \Illuminate\Contracts\Auth\Access\Gate $gate 23 | * @return void 24 | */ 25 | public function boot(GateContract $gate) 26 | { 27 | $this->registerPolicies($gate); 28 | 29 | // 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /laravel/app/Providers/EventServiceProvider.php: -------------------------------------------------------------------------------- 1 | [ 17 | 'App\Listeners\EventListener', 18 | ], 19 | ]; 20 | 21 | /** 22 | * Register any other events for your application. 23 | * 24 | * @param \Illuminate\Contracts\Events\Dispatcher $events 25 | * @return void 26 | */ 27 | public function boot(DispatcherContract $events) 28 | { 29 | parent::boot($events); 30 | 31 | // 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /laravel/app/Providers/RouteServiceProvider.php: -------------------------------------------------------------------------------- 1 | mapWebRoutes($router); 41 | 42 | // 43 | } 44 | 45 | /** 46 | * Define the "web" routes for the application. 47 | * 48 | * These routes all receive session state, CSRF protection, etc. 49 | * 50 | * @param \Illuminate\Routing\Router $router 51 | * @return void 52 | */ 53 | protected function mapWebRoutes(Router $router) 54 | { 55 | $router->group([ 56 | 'namespace' => $this->namespace, 'middleware' => 'web', 57 | ], function ($router) { 58 | require app_path('Http/routes.php'); 59 | }); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /laravel/app/User.php: -------------------------------------------------------------------------------- 1 | make(Illuminate\Contracts\Console\Kernel::class); 32 | 33 | $status = $kernel->handle( 34 | $input = new Symfony\Component\Console\Input\ArgvInput, 35 | new Symfony\Component\Console\Output\ConsoleOutput 36 | ); 37 | 38 | /* 39 | |-------------------------------------------------------------------------- 40 | | Shutdown The Application 41 | |-------------------------------------------------------------------------- 42 | | 43 | | Once Artisan has finished running. We will fire off the shutdown events 44 | | so that any final work may be done by the application before we shut 45 | | down the process. This is the last thing to happen to the request. 46 | | 47 | */ 48 | 49 | $kernel->terminate($input, $status); 50 | 51 | exit($status); 52 | -------------------------------------------------------------------------------- /laravel/bootstrap/app.php: -------------------------------------------------------------------------------- 1 | singleton( 30 | Illuminate\Contracts\Http\Kernel::class, 31 | App\Http\Kernel::class 32 | ); 33 | 34 | $app->singleton( 35 | Illuminate\Contracts\Console\Kernel::class, 36 | App\Console\Kernel::class 37 | ); 38 | 39 | $app->singleton( 40 | Illuminate\Contracts\Debug\ExceptionHandler::class, 41 | App\Exceptions\Handler::class 42 | ); 43 | 44 | /* 45 | |-------------------------------------------------------------------------- 46 | | Return The Application 47 | |-------------------------------------------------------------------------- 48 | | 49 | | This script returns the application instance. The instance is given to 50 | | the calling script so we can separate the building of the instances 51 | | from the actual running of the application and sending responses. 52 | | 53 | */ 54 | 55 | return $app; 56 | -------------------------------------------------------------------------------- /laravel/bootstrap/autoload.php: -------------------------------------------------------------------------------- 1 | =5.5.9", 9 | "laravel/framework": "5.2.*", 10 | "aws/aws-sdk-php": "3.18.14", 11 | "league/flysystem-aws-s3-v3": "~1.0" 12 | }, 13 | "require-dev": { 14 | "fzaninotto/faker": "~1.4", 15 | "mockery/mockery": "0.9.*", 16 | "phpunit/phpunit": "~4.0", 17 | "symfony/css-selector": "2.8.*|3.0.*", 18 | "symfony/dom-crawler": "2.8.*|3.0.*" 19 | }, 20 | "autoload": { 21 | "classmap": [ 22 | "database" 23 | ], 24 | "psr-4": { 25 | "App\\": "app/" 26 | } 27 | }, 28 | "autoload-dev": { 29 | "classmap": [ 30 | "tests/TestCase.php" 31 | ] 32 | }, 33 | "scripts": { 34 | "post-root-package-install": [ 35 | "php -r \"copy('.env.example', '.env');\"" 36 | ], 37 | "post-create-project-cmd": [ 38 | "php artisan key:generate" 39 | ], 40 | "post-install-cmd": [ 41 | "Illuminate\\Foundation\\ComposerScripts::postInstall", 42 | "php artisan optimize" 43 | ], 44 | "post-update-cmd": [ 45 | "Illuminate\\Foundation\\ComposerScripts::postUpdate", 46 | "php artisan optimize" 47 | ] 48 | }, 49 | "config": { 50 | "preferred-install": "dist" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /laravel/config/app.php: -------------------------------------------------------------------------------- 1 | env('APP_ENV', 'production'), 17 | 18 | /* 19 | |-------------------------------------------------------------------------- 20 | | Application Debug Mode 21 | |-------------------------------------------------------------------------- 22 | | 23 | | When your application is in debug mode, detailed error messages with 24 | | stack traces will be shown on every error that occurs within your 25 | | application. If disabled, a simple generic error page is shown. 26 | | 27 | */ 28 | 29 | 'debug' => env('APP_DEBUG', false), 30 | 31 | /* 32 | |-------------------------------------------------------------------------- 33 | | Application URL 34 | |-------------------------------------------------------------------------- 35 | | 36 | | This URL is used by the console to properly generate URLs when using 37 | | the Artisan command line tool. You should set this to the root of 38 | | your application so that it is used when running Artisan tasks. 39 | | 40 | */ 41 | 42 | 'url' => env('APP_URL', 'http://localhost'), 43 | 44 | /* 45 | |-------------------------------------------------------------------------- 46 | | Application Timezone 47 | |-------------------------------------------------------------------------- 48 | | 49 | | Here you may specify the default timezone for your application, which 50 | | will be used by the PHP date and date-time functions. We have gone 51 | | ahead and set this to a sensible default for you out of the box. 52 | | 53 | */ 54 | 55 | 'timezone' => 'UTC', 56 | 57 | /* 58 | |-------------------------------------------------------------------------- 59 | | Application Locale Configuration 60 | |-------------------------------------------------------------------------- 61 | | 62 | | The application locale determines the default locale that will be used 63 | | by the translation service provider. You are free to set this value 64 | | to any of the locales which will be supported by the application. 65 | | 66 | */ 67 | 68 | 'locale' => 'en', 69 | 70 | /* 71 | |-------------------------------------------------------------------------- 72 | | Application Fallback Locale 73 | |-------------------------------------------------------------------------- 74 | | 75 | | The fallback locale determines the locale to use when the current one 76 | | is not available. You may change the value to correspond to any of 77 | | the language folders that are provided through your application. 78 | | 79 | */ 80 | 81 | 'fallback_locale' => 'en', 82 | 83 | /* 84 | |-------------------------------------------------------------------------- 85 | | Encryption Key 86 | |-------------------------------------------------------------------------- 87 | | 88 | | This key is used by the Illuminate encrypter service and should be set 89 | | to a random, 32 character string, otherwise these encrypted strings 90 | | will not be safe. Please do this before deploying an application! 91 | | 92 | */ 93 | 94 | 'key' => env('APP_KEY'), 95 | 96 | 'cipher' => 'AES-256-CBC', 97 | 98 | /* 99 | |-------------------------------------------------------------------------- 100 | | Logging Configuration 101 | |-------------------------------------------------------------------------- 102 | | 103 | | Here you may configure the log settings for your application. Out of 104 | | the box, Laravel uses the Monolog PHP logging library. This gives 105 | | you a variety of powerful log handlers / formatters to utilize. 106 | | 107 | | Available Settings: "single", "daily", "syslog", "errorlog" 108 | | 109 | */ 110 | 111 | 'log' => env('APP_LOG', 'single'), 112 | 113 | /* 114 | |-------------------------------------------------------------------------- 115 | | Autoloaded Service Providers 116 | |-------------------------------------------------------------------------- 117 | | 118 | | The service providers listed here will be automatically loaded on the 119 | | request to your application. Feel free to add your own services to 120 | | this array to grant expanded functionality to your applications. 121 | | 122 | */ 123 | 124 | 'providers' => [ 125 | 126 | /* 127 | * Laravel Framework Service Providers... 128 | */ 129 | Illuminate\Auth\AuthServiceProvider::class, 130 | Illuminate\Broadcasting\BroadcastServiceProvider::class, 131 | Illuminate\Bus\BusServiceProvider::class, 132 | Illuminate\Cache\CacheServiceProvider::class, 133 | Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class, 134 | Illuminate\Cookie\CookieServiceProvider::class, 135 | Illuminate\Database\DatabaseServiceProvider::class, 136 | Illuminate\Encryption\EncryptionServiceProvider::class, 137 | Illuminate\Filesystem\FilesystemServiceProvider::class, 138 | Illuminate\Foundation\Providers\FoundationServiceProvider::class, 139 | Illuminate\Hashing\HashServiceProvider::class, 140 | Illuminate\Mail\MailServiceProvider::class, 141 | Illuminate\Pagination\PaginationServiceProvider::class, 142 | Illuminate\Pipeline\PipelineServiceProvider::class, 143 | Illuminate\Queue\QueueServiceProvider::class, 144 | Illuminate\Redis\RedisServiceProvider::class, 145 | Illuminate\Auth\Passwords\PasswordResetServiceProvider::class, 146 | Illuminate\Session\SessionServiceProvider::class, 147 | Illuminate\Translation\TranslationServiceProvider::class, 148 | Illuminate\Validation\ValidationServiceProvider::class, 149 | Illuminate\View\ViewServiceProvider::class, 150 | 151 | /* 152 | * Application Service Providers... 153 | */ 154 | App\Providers\AppServiceProvider::class, 155 | App\Providers\AuthServiceProvider::class, 156 | App\Providers\EventServiceProvider::class, 157 | App\Providers\RouteServiceProvider::class, 158 | 159 | ], 160 | 161 | /* 162 | |-------------------------------------------------------------------------- 163 | | Class Aliases 164 | |-------------------------------------------------------------------------- 165 | | 166 | | This array of class aliases will be registered when this application 167 | | is started. However, feel free to register as many as you wish as 168 | | the aliases are "lazy" loaded so they don't hinder performance. 169 | | 170 | */ 171 | 172 | 'aliases' => [ 173 | 174 | 'App' => Illuminate\Support\Facades\App::class, 175 | 'Artisan' => Illuminate\Support\Facades\Artisan::class, 176 | 'Auth' => Illuminate\Support\Facades\Auth::class, 177 | 'Blade' => Illuminate\Support\Facades\Blade::class, 178 | 'Cache' => Illuminate\Support\Facades\Cache::class, 179 | 'Config' => Illuminate\Support\Facades\Config::class, 180 | 'Cookie' => Illuminate\Support\Facades\Cookie::class, 181 | 'Crypt' => Illuminate\Support\Facades\Crypt::class, 182 | 'DB' => Illuminate\Support\Facades\DB::class, 183 | 'Eloquent' => Illuminate\Database\Eloquent\Model::class, 184 | 'Event' => Illuminate\Support\Facades\Event::class, 185 | 'File' => Illuminate\Support\Facades\File::class, 186 | 'Gate' => Illuminate\Support\Facades\Gate::class, 187 | 'Hash' => Illuminate\Support\Facades\Hash::class, 188 | 'Lang' => Illuminate\Support\Facades\Lang::class, 189 | 'Log' => Illuminate\Support\Facades\Log::class, 190 | 'Mail' => Illuminate\Support\Facades\Mail::class, 191 | 'Password' => Illuminate\Support\Facades\Password::class, 192 | 'Queue' => Illuminate\Support\Facades\Queue::class, 193 | 'Redirect' => Illuminate\Support\Facades\Redirect::class, 194 | 'Redis' => Illuminate\Support\Facades\Redis::class, 195 | 'Request' => Illuminate\Support\Facades\Request::class, 196 | 'Response' => Illuminate\Support\Facades\Response::class, 197 | 'Route' => Illuminate\Support\Facades\Route::class, 198 | 'Schema' => Illuminate\Support\Facades\Schema::class, 199 | 'Session' => Illuminate\Support\Facades\Session::class, 200 | 'Storage' => Illuminate\Support\Facades\Storage::class, 201 | 'URL' => Illuminate\Support\Facades\URL::class, 202 | 'Validator' => Illuminate\Support\Facades\Validator::class, 203 | 'View' => Illuminate\Support\Facades\View::class, 204 | 205 | ], 206 | 207 | ]; 208 | -------------------------------------------------------------------------------- /laravel/config/auth.php: -------------------------------------------------------------------------------- 1 | [ 17 | 'guard' => 'web', 18 | 'passwords' => 'users', 19 | ], 20 | 21 | /* 22 | |-------------------------------------------------------------------------- 23 | | Authentication Guards 24 | |-------------------------------------------------------------------------- 25 | | 26 | | Next, you may define every authentication guard for your application. 27 | | Of course, a great default configuration has been defined for you 28 | | here which uses session storage and the Eloquent user provider. 29 | | 30 | | All authentication drivers have a user provider. This defines how the 31 | | users are actually retrieved out of your database or other storage 32 | | mechanisms used by this application to persist your user's data. 33 | | 34 | | Supported: "session", "token" 35 | | 36 | */ 37 | 38 | 'guards' => [ 39 | 'web' => [ 40 | 'driver' => 'session', 41 | 'provider' => 'users', 42 | ], 43 | 44 | 'api' => [ 45 | 'driver' => 'token', 46 | 'provider' => 'users', 47 | ], 48 | ], 49 | 50 | /* 51 | |-------------------------------------------------------------------------- 52 | | User Providers 53 | |-------------------------------------------------------------------------- 54 | | 55 | | All authentication drivers have a user provider. This defines how the 56 | | users are actually retrieved out of your database or other storage 57 | | mechanisms used by this application to persist your user's data. 58 | | 59 | | If you have multiple user tables or models you may configure multiple 60 | | sources which represent each model / table. These sources may then 61 | | be assigned to any extra authentication guards you have defined. 62 | | 63 | | Supported: "database", "eloquent" 64 | | 65 | */ 66 | 67 | 'providers' => [ 68 | 'users' => [ 69 | 'driver' => 'eloquent', 70 | 'model' => App\User::class, 71 | ], 72 | 73 | // 'users' => [ 74 | // 'driver' => 'database', 75 | // 'table' => 'users', 76 | // ], 77 | ], 78 | 79 | /* 80 | |-------------------------------------------------------------------------- 81 | | Resetting Passwords 82 | |-------------------------------------------------------------------------- 83 | | 84 | | Here you may set the options for resetting passwords including the view 85 | | that is your password reset e-mail. You may also set the name of the 86 | | table that maintains all of the reset tokens for your application. 87 | | 88 | | You may specify multiple password reset configurations if you have more 89 | | than one user table or model in the application and you want to have 90 | | separate password reset settings based on the specific user types. 91 | | 92 | | The expire time is the number of minutes that the reset token should be 93 | | considered valid. This security feature keeps tokens short-lived so 94 | | they have less time to be guessed. You may change this as needed. 95 | | 96 | */ 97 | 98 | 'passwords' => [ 99 | 'users' => [ 100 | 'provider' => 'users', 101 | 'email' => 'auth.emails.password', 102 | 'table' => 'password_resets', 103 | 'expire' => 60, 104 | ], 105 | ], 106 | 107 | ]; 108 | -------------------------------------------------------------------------------- /laravel/config/broadcasting.php: -------------------------------------------------------------------------------- 1 | env('BROADCAST_DRIVER', 'pusher'), 17 | 18 | /* 19 | |-------------------------------------------------------------------------- 20 | | Broadcast Connections 21 | |-------------------------------------------------------------------------- 22 | | 23 | | Here you may define all of the broadcast connections that will be used 24 | | to broadcast events to other systems or over websockets. Samples of 25 | | each available type of connection are provided inside this array. 26 | | 27 | */ 28 | 29 | 'connections' => [ 30 | 31 | 'pusher' => [ 32 | 'driver' => 'pusher', 33 | 'key' => env('PUSHER_KEY'), 34 | 'secret' => env('PUSHER_SECRET'), 35 | 'app_id' => env('PUSHER_APP_ID'), 36 | 'options' => [ 37 | // 38 | ], 39 | ], 40 | 41 | 'redis' => [ 42 | 'driver' => 'redis', 43 | 'connection' => 'default', 44 | ], 45 | 46 | 'log' => [ 47 | 'driver' => 'log', 48 | ], 49 | 50 | ], 51 | 52 | ]; 53 | -------------------------------------------------------------------------------- /laravel/config/cache.php: -------------------------------------------------------------------------------- 1 | env('CACHE_DRIVER', 'file'), 17 | 18 | /* 19 | |-------------------------------------------------------------------------- 20 | | Cache Stores 21 | |-------------------------------------------------------------------------- 22 | | 23 | | Here you may define all of the cache "stores" for your application as 24 | | well as their drivers. You may even define multiple stores for the 25 | | same cache driver to group types of items stored in your caches. 26 | | 27 | */ 28 | 29 | 'stores' => [ 30 | 31 | 'apc' => [ 32 | 'driver' => 'apc', 33 | ], 34 | 35 | 'array' => [ 36 | 'driver' => 'array', 37 | ], 38 | 39 | 'database' => [ 40 | 'driver' => 'database', 41 | 'table' => 'cache', 42 | 'connection' => null, 43 | ], 44 | 45 | 'file' => [ 46 | 'driver' => 'file', 47 | 'path' => storage_path('framework/cache'), 48 | ], 49 | 50 | 'memcached' => [ 51 | 'driver' => 'memcached', 52 | 'servers' => [ 53 | [ 54 | 'host' => env('MEMCACHED_HOST', '127.0.0.1'), 55 | 'port' => env('MEMCACHED_PORT', 11211), 56 | 'weight' => 100, 57 | ], 58 | ], 59 | ], 60 | 61 | 'redis' => [ 62 | 'driver' => 'redis', 63 | 'connection' => 'default', 64 | ], 65 | 66 | ], 67 | 68 | /* 69 | |-------------------------------------------------------------------------- 70 | | Cache Key Prefix 71 | |-------------------------------------------------------------------------- 72 | | 73 | | When utilizing a RAM based store such as APC or Memcached, there might 74 | | be other applications utilizing the same cache. So, we'll specify a 75 | | value to get prefixed to all our keys so we can avoid collisions. 76 | | 77 | */ 78 | 79 | 'prefix' => 'laravel', 80 | 81 | ]; 82 | -------------------------------------------------------------------------------- /laravel/config/compile.php: -------------------------------------------------------------------------------- 1 | [ 17 | // 18 | ], 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Compiled File Providers 23 | |-------------------------------------------------------------------------- 24 | | 25 | | Here you may list service providers which define a "compiles" function 26 | | that returns additional files that should be compiled, providing an 27 | | easy way to get common files from any packages you are utilizing. 28 | | 29 | */ 30 | 31 | 'providers' => [ 32 | // 33 | ], 34 | 35 | ]; 36 | -------------------------------------------------------------------------------- /laravel/config/database.php: -------------------------------------------------------------------------------- 1 | PDO::FETCH_CLASS, 17 | 18 | /* 19 | |-------------------------------------------------------------------------- 20 | | Default Database Connection Name 21 | |-------------------------------------------------------------------------- 22 | | 23 | | Here you may specify which of the database connections below you wish 24 | | to use as your default connection for all database work. Of course 25 | | you may use many connections at once using the Database library. 26 | | 27 | */ 28 | 29 | 'default' => env('DB_CONNECTION', 'mysql'), 30 | 31 | /* 32 | |-------------------------------------------------------------------------- 33 | | Database Connections 34 | |-------------------------------------------------------------------------- 35 | | 36 | | Here are each of the database connections setup for your application. 37 | | Of course, examples of configuring each database platform that is 38 | | supported by Laravel is shown below to make development simple. 39 | | 40 | | 41 | | All database work in Laravel is done through the PHP PDO facilities 42 | | so make sure you have the driver for your particular database of 43 | | choice installed on your machine before you begin development. 44 | | 45 | */ 46 | 47 | 'connections' => [ 48 | 49 | 'sqlite' => [ 50 | 'driver' => 'sqlite', 51 | 'database' => env('DB_DATABASE', database_path('database.sqlite')), 52 | 'prefix' => '', 53 | ], 54 | 55 | 'mysql' => [ 56 | 'driver' => 'mysql', 57 | 'host' => env('DB_HOST', 'localhost'), 58 | 'port' => env('DB_PORT', '3306'), 59 | 'database' => env('DB_DATABASE', 'forge'), 60 | 'username' => env('DB_USERNAME', 'forge'), 61 | 'password' => env('DB_PASSWORD', ''), 62 | 'charset' => 'utf8', 63 | 'collation' => 'utf8_unicode_ci', 64 | 'prefix' => '', 65 | 'strict' => false, 66 | 'engine' => null, 67 | ], 68 | 69 | 'pgsql' => [ 70 | 'driver' => 'pgsql', 71 | 'host' => env('DB_HOST', 'localhost'), 72 | 'port' => env('DB_PORT', '5432'), 73 | 'database' => env('DB_DATABASE', 'forge'), 74 | 'username' => env('DB_USERNAME', 'forge'), 75 | 'password' => env('DB_PASSWORD', ''), 76 | 'charset' => 'utf8', 77 | 'prefix' => '', 78 | 'schema' => 'public', 79 | ], 80 | 81 | ], 82 | 83 | /* 84 | |-------------------------------------------------------------------------- 85 | | Migration Repository Table 86 | |-------------------------------------------------------------------------- 87 | | 88 | | This table keeps track of all the migrations that have already run for 89 | | your application. Using this information, we can determine which of 90 | | the migrations on disk haven't actually been run in the database. 91 | | 92 | */ 93 | 94 | 'migrations' => 'migrations', 95 | 96 | /* 97 | |-------------------------------------------------------------------------- 98 | | Redis Databases 99 | |-------------------------------------------------------------------------- 100 | | 101 | | Redis is an open source, fast, and advanced key-value store that also 102 | | provides a richer set of commands than a typical key-value systems 103 | | such as APC or Memcached. Laravel makes it easy to dig right in. 104 | | 105 | */ 106 | 107 | 'redis' => [ 108 | 109 | 'cluster' => false, 110 | 111 | 'default' => [ 112 | 'host' => env('REDIS_HOST', 'localhost'), 113 | 'password' => env('REDIS_PASSWORD', null), 114 | 'port' => env('REDIS_PORT', 6379), 115 | 'database' => 0, 116 | ], 117 | 118 | ], 119 | 120 | ]; 121 | -------------------------------------------------------------------------------- /laravel/config/filesystems.php: -------------------------------------------------------------------------------- 1 | 's3', 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Default Cloud Filesystem Disk 23 | |-------------------------------------------------------------------------- 24 | | 25 | | Many applications store files both locally and in the cloud. For this 26 | | reason, you may specify a default "cloud" driver here. This driver 27 | | will be bound as the Cloud disk implementation in the container. 28 | | 29 | */ 30 | 31 | 'cloud' => 's3', 32 | 33 | /* 34 | |-------------------------------------------------------------------------- 35 | | Filesystem Disks 36 | |-------------------------------------------------------------------------- 37 | | 38 | | Here you may configure as many filesystem "disks" as you wish, and you 39 | | may even configure multiple disks of the same driver. Defaults have 40 | | been setup for each driver as an example of the required options. 41 | | 42 | */ 43 | 44 | 'disks' => [ 45 | 46 | 'local' => [ 47 | 'driver' => 'local', 48 | 'root' => storage_path('app'), 49 | ], 50 | 51 | 'public' => [ 52 | 'driver' => 'local', 53 | 'root' => storage_path('app/public'), 54 | 'visibility' => 'public', 55 | ], 56 | 57 | 's3' => [ 58 | 'driver' => 's3', 59 | 'key' => null, 60 | 'secret' => null, 61 | 'region' => env('AWS_REGION'), 62 | 'bucket' => env('AWS_S3_BUCKET'), 63 | ], 64 | 65 | ], 66 | 67 | ]; 68 | -------------------------------------------------------------------------------- /laravel/config/mail.php: -------------------------------------------------------------------------------- 1 | env('MAIL_DRIVER', 'smtp'), 20 | 21 | /* 22 | |-------------------------------------------------------------------------- 23 | | SMTP Host Address 24 | |-------------------------------------------------------------------------- 25 | | 26 | | Here you may provide the host address of the SMTP server used by your 27 | | applications. A default option is provided that is compatible with 28 | | the Mailgun mail service which will provide reliable deliveries. 29 | | 30 | */ 31 | 32 | 'host' => env('MAIL_HOST', 'smtp.mailgun.org'), 33 | 34 | /* 35 | |-------------------------------------------------------------------------- 36 | | SMTP Host Port 37 | |-------------------------------------------------------------------------- 38 | | 39 | | This is the SMTP port used by your application to deliver e-mails to 40 | | users of the application. Like the host we have set this value to 41 | | stay compatible with the Mailgun e-mail application by default. 42 | | 43 | */ 44 | 45 | 'port' => env('MAIL_PORT', 587), 46 | 47 | /* 48 | |-------------------------------------------------------------------------- 49 | | Global "From" Address 50 | |-------------------------------------------------------------------------- 51 | | 52 | | You may wish for all e-mails sent by your application to be sent from 53 | | the same address. Here, you may specify a name and address that is 54 | | used globally for all e-mails that are sent by your application. 55 | | 56 | */ 57 | 58 | 'from' => ['address' => null, 'name' => null], 59 | 60 | /* 61 | |-------------------------------------------------------------------------- 62 | | E-Mail Encryption Protocol 63 | |-------------------------------------------------------------------------- 64 | | 65 | | Here you may specify the encryption protocol that should be used when 66 | | the application send e-mail messages. A sensible default using the 67 | | transport layer security protocol should provide great security. 68 | | 69 | */ 70 | 71 | 'encryption' => env('MAIL_ENCRYPTION', 'tls'), 72 | 73 | /* 74 | |-------------------------------------------------------------------------- 75 | | SMTP Server Username 76 | |-------------------------------------------------------------------------- 77 | | 78 | | If your SMTP server requires a username for authentication, you should 79 | | set it here. This will get used to authenticate with your server on 80 | | connection. You may also set the "password" value below this one. 81 | | 82 | */ 83 | 84 | 'username' => env('MAIL_USERNAME'), 85 | 86 | /* 87 | |-------------------------------------------------------------------------- 88 | | SMTP Server Password 89 | |-------------------------------------------------------------------------- 90 | | 91 | | Here you may set the password required by your SMTP server to send out 92 | | messages from your application. This will be given to the server on 93 | | connection so that the application will be able to send messages. 94 | | 95 | */ 96 | 97 | 'password' => env('MAIL_PASSWORD'), 98 | 99 | /* 100 | |-------------------------------------------------------------------------- 101 | | Sendmail System Path 102 | |-------------------------------------------------------------------------- 103 | | 104 | | When using the "sendmail" driver to send e-mails, we will need to know 105 | | the path to where Sendmail lives on this server. A default path has 106 | | been provided here, which will work well on most of your systems. 107 | | 108 | */ 109 | 110 | 'sendmail' => '/usr/sbin/sendmail -bs', 111 | 112 | ]; 113 | -------------------------------------------------------------------------------- /laravel/config/queue.php: -------------------------------------------------------------------------------- 1 | env('QUEUE_DRIVER', 'sync'), 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Queue Connections 23 | |-------------------------------------------------------------------------- 24 | | 25 | | Here you may configure the connection information for each server that 26 | | is used by your application. A default configuration has been added 27 | | for each back-end shipped with Laravel. You are free to add more. 28 | | 29 | */ 30 | 31 | 'connections' => [ 32 | 33 | 'sync' => [ 34 | 'driver' => 'sync', 35 | ], 36 | 37 | 'database' => [ 38 | 'driver' => 'database', 39 | 'table' => 'jobs', 40 | 'queue' => 'default', 41 | 'expire' => 60, 42 | ], 43 | 44 | 'beanstalkd' => [ 45 | 'driver' => 'beanstalkd', 46 | 'host' => 'localhost', 47 | 'queue' => 'default', 48 | 'ttr' => 60, 49 | ], 50 | 51 | 'sqs' => [ 52 | 'driver' => 'sqs', 53 | 'key' => null, 54 | 'secret' => null, 55 | 'prefix' => env('AWS_SQS_PREFIX'), 56 | 'queue' => env('AWS_SQS_QUEUE'), 57 | 'region' => env('AWS_REGION'), 58 | ], 59 | 60 | 'redis' => [ 61 | 'driver' => 'redis', 62 | 'connection' => 'default', 63 | 'queue' => 'default', 64 | 'expire' => 60, 65 | ], 66 | 67 | ], 68 | 69 | /* 70 | |-------------------------------------------------------------------------- 71 | | Failed Queue Jobs 72 | |-------------------------------------------------------------------------- 73 | | 74 | | These options configure the behavior of failed queue job logging so you 75 | | can control which database and table are used to store the jobs that 76 | | have failed. You may change them to any database / table you wish. 77 | | 78 | */ 79 | 80 | 'failed' => [ 81 | 'database' => env('DB_CONNECTION', 'mysql'), 82 | 'table' => 'failed_jobs', 83 | ], 84 | 85 | ]; 86 | -------------------------------------------------------------------------------- /laravel/config/services.php: -------------------------------------------------------------------------------- 1 | [ 18 | 'domain' => env('MAILGUN_DOMAIN'), 19 | 'secret' => env('MAILGUN_SECRET'), 20 | ], 21 | 22 | 'mandrill' => [ 23 | 'secret' => env('MANDRILL_SECRET'), 24 | ], 25 | 26 | 'ses' => [ 27 | 'key' => null, 28 | 'secret' => null, 29 | 'region' => env('AWS_REGION'), 30 | ], 31 | 32 | 'sparkpost' => [ 33 | 'secret' => env('SPARKPOST_SECRET'), 34 | ], 35 | 36 | 'stripe' => [ 37 | 'model' => App\User::class, 38 | 'key' => env('STRIPE_KEY'), 39 | 'secret' => env('STRIPE_SECRET'), 40 | ], 41 | 42 | ]; 43 | -------------------------------------------------------------------------------- /laravel/config/session.php: -------------------------------------------------------------------------------- 1 | env('SESSION_DRIVER', 'file'), 20 | 21 | /* 22 | |-------------------------------------------------------------------------- 23 | | Session Lifetime 24 | |-------------------------------------------------------------------------- 25 | | 26 | | Here you may specify the number of minutes that you wish the session 27 | | to be allowed to remain idle before it expires. If you want them 28 | | to immediately expire on the browser closing, set that option. 29 | | 30 | */ 31 | 32 | 'lifetime' => 120, 33 | 34 | 'expire_on_close' => false, 35 | 36 | /* 37 | |-------------------------------------------------------------------------- 38 | | Session Encryption 39 | |-------------------------------------------------------------------------- 40 | | 41 | | This option allows you to easily specify that all of your session data 42 | | should be encrypted before it is stored. All encryption will be run 43 | | automatically by Laravel and you can use the Session like normal. 44 | | 45 | */ 46 | 47 | 'encrypt' => false, 48 | 49 | /* 50 | |-------------------------------------------------------------------------- 51 | | Session File Location 52 | |-------------------------------------------------------------------------- 53 | | 54 | | When using the native session driver, we need a location where session 55 | | files may be stored. A default has been set for you but a different 56 | | location may be specified. This is only needed for file sessions. 57 | | 58 | */ 59 | 60 | 'files' => storage_path('framework/sessions'), 61 | 62 | /* 63 | |-------------------------------------------------------------------------- 64 | | Session Database Connection 65 | |-------------------------------------------------------------------------- 66 | | 67 | | When using the "database" or "redis" session drivers, you may specify a 68 | | connection that should be used to manage these sessions. This should 69 | | correspond to a connection in your database configuration options. 70 | | 71 | */ 72 | 73 | 'connection' => null, 74 | 75 | /* 76 | |-------------------------------------------------------------------------- 77 | | Session Database Table 78 | |-------------------------------------------------------------------------- 79 | | 80 | | When using the "database" session driver, you may specify the table we 81 | | should use to manage the sessions. Of course, a sensible default is 82 | | provided for you; however, you are free to change this as needed. 83 | | 84 | */ 85 | 86 | 'table' => 'sessions', 87 | 88 | /* 89 | |-------------------------------------------------------------------------- 90 | | Session Sweeping Lottery 91 | |-------------------------------------------------------------------------- 92 | | 93 | | Some session drivers must manually sweep their storage location to get 94 | | rid of old sessions from storage. Here are the chances that it will 95 | | happen on a given request. By default, the odds are 2 out of 100. 96 | | 97 | */ 98 | 99 | 'lottery' => [2, 100], 100 | 101 | /* 102 | |-------------------------------------------------------------------------- 103 | | Session Cookie Name 104 | |-------------------------------------------------------------------------- 105 | | 106 | | Here you may change the name of the cookie used to identify a session 107 | | instance by ID. The name specified here will get used every time a 108 | | new session cookie is created by the framework for every driver. 109 | | 110 | */ 111 | 112 | 'cookie' => 'laravel_session', 113 | 114 | /* 115 | |-------------------------------------------------------------------------- 116 | | Session Cookie Path 117 | |-------------------------------------------------------------------------- 118 | | 119 | | The session cookie path determines the path for which the cookie will 120 | | be regarded as available. Typically, this will be the root path of 121 | | your application but you are free to change this when necessary. 122 | | 123 | */ 124 | 125 | 'path' => '/', 126 | 127 | /* 128 | |-------------------------------------------------------------------------- 129 | | Session Cookie Domain 130 | |-------------------------------------------------------------------------- 131 | | 132 | | Here you may change the domain of the cookie used to identify a session 133 | | in your application. This will determine which domains the cookie is 134 | | available to in your application. A sensible default has been set. 135 | | 136 | */ 137 | 138 | 'domain' => null, 139 | 140 | /* 141 | |-------------------------------------------------------------------------- 142 | | HTTPS Only Cookies 143 | |-------------------------------------------------------------------------- 144 | | 145 | | By setting this option to true, session cookies will only be sent back 146 | | to the server if the browser has a HTTPS connection. This will keep 147 | | the cookie from being sent to you if it can not be done securely. 148 | | 149 | */ 150 | 151 | 'secure' => false, 152 | 153 | /* 154 | |-------------------------------------------------------------------------- 155 | | HTTP Access Only 156 | |-------------------------------------------------------------------------- 157 | | 158 | | Setting this value to true will prevent JavaScript from accessing the 159 | | value of the cookie and the cookie will only be accessible through 160 | | the HTTP protocol. You are free to modify this option if needed. 161 | | 162 | */ 163 | 164 | 'http_only' => true, 165 | 166 | ]; 167 | -------------------------------------------------------------------------------- /laravel/config/view.php: -------------------------------------------------------------------------------- 1 | [ 17 | realpath(base_path('resources/views')), 18 | ], 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Compiled View Path 23 | |-------------------------------------------------------------------------- 24 | | 25 | | This option determines where all the compiled Blade templates will be 26 | | stored for your application. Typically, this is within the storage 27 | | directory. However, as usual, you are free to change this value. 28 | | 29 | */ 30 | 31 | 'compiled' => realpath(storage_path('framework/views')), 32 | 33 | ]; 34 | -------------------------------------------------------------------------------- /laravel/database/.gitignore: -------------------------------------------------------------------------------- 1 | *.sqlite 2 | -------------------------------------------------------------------------------- /laravel/database/factories/ModelFactory.php: -------------------------------------------------------------------------------- 1 | define(App\User::class, function (Faker\Generator $faker) { 15 | return [ 16 | 'name' => $faker->name, 17 | 'email' => $faker->safeEmail, 18 | 'password' => bcrypt(str_random(10)), 19 | 'remember_token' => str_random(10), 20 | ]; 21 | }); 22 | -------------------------------------------------------------------------------- /laravel/database/migrations/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /laravel/database/migrations/2014_10_12_000000_create_users_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 17 | $table->string('name'); 18 | $table->string('email')->unique(); 19 | $table->string('password'); 20 | $table->rememberToken(); 21 | $table->timestamps(); 22 | }); 23 | } 24 | 25 | /** 26 | * Reverse the migrations. 27 | * 28 | * @return void 29 | */ 30 | public function down() 31 | { 32 | Schema::drop('users'); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /laravel/database/migrations/2014_10_12_100000_create_password_resets_table.php: -------------------------------------------------------------------------------- 1 | string('email')->index(); 17 | $table->string('token')->index(); 18 | $table->timestamp('created_at'); 19 | }); 20 | } 21 | 22 | /** 23 | * Reverse the migrations. 24 | * 25 | * @return void 26 | */ 27 | public function down() 28 | { 29 | Schema::drop('password_resets'); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /laravel/database/seeds/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /laravel/database/seeds/DatabaseSeeder.php: -------------------------------------------------------------------------------- 1 | call(UsersTableSeeder::class); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /laravel/env: -------------------------------------------------------------------------------- 1 | APP_ENV=local 2 | APP_DEBUG=true 3 | APP_KEY=MErb5L45R82TyBLnDG4qQSpLaFbhBZsU 4 | APP_URL=http://localhost 5 | 6 | DB_CONNECTION=mysql 7 | DB_HOST=db.rossedman.internal 8 | DB_PORT=3306 9 | DB_DATABASE=basicapp 10 | DB_USERNAME=admin 11 | DB_PASSWORD=password 12 | 13 | CACHE_DRIVER=memcached 14 | SESSION_DRIVER=memcached 15 | QUEUE_DRIVER=sqs 16 | 17 | MEMCACHED_HOST=cache.rossedman.internal 18 | MEMCACHED_PORT=11211 19 | 20 | AWS_REGION=us-west-2 21 | AWS_S3_BUCKET=testapp.storage 22 | AWS_SQS_QUEUE=basicapp-queue 23 | AWS_SQS_PREFIX=https://sqs.us-west-2.amazonaws.com/351353229602/ 24 | 25 | MAIL_DRIVER=ses 26 | -------------------------------------------------------------------------------- /laravel/gulpfile.js: -------------------------------------------------------------------------------- 1 | var elixir = require('laravel-elixir'); 2 | 3 | /* 4 | |-------------------------------------------------------------------------- 5 | | Elixir Asset Management 6 | |-------------------------------------------------------------------------- 7 | | 8 | | Elixir provides a clean, fluent API for defining some basic Gulp tasks 9 | | for your Laravel application. By default, we are compiling the Sass 10 | | file for our application, as well as publishing vendor resources. 11 | | 12 | */ 13 | 14 | elixir(function(mix) { 15 | mix.sass('app.scss'); 16 | }); 17 | -------------------------------------------------------------------------------- /laravel/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "prod": "gulp --production", 5 | "dev": "gulp watch" 6 | }, 7 | "devDependencies": { 8 | "gulp": "^3.9.1", 9 | "laravel-elixir": "^5.0.0", 10 | "bootstrap-sass": "^3.3.0" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /laravel/phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | ./tests 14 | 15 | 16 | 17 | 18 | ./app 19 | 20 | ./app/Http/routes.php 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /laravel/public/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | 3 | Options -MultiViews 4 | 5 | 6 | RewriteEngine On 7 | 8 | # Redirect Trailing Slashes If Not A Folder... 9 | RewriteCond %{REQUEST_FILENAME} !-d 10 | RewriteRule ^(.*)/$ /$1 [L,R=301] 11 | 12 | # Handle Front Controller... 13 | RewriteCond %{REQUEST_FILENAME} !-d 14 | RewriteCond %{REQUEST_FILENAME} !-f 15 | RewriteRule ^ index.php [L] 16 | 17 | # Handle Authorization Header 18 | RewriteCond %{HTTP:Authorization} . 19 | RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] 20 | 21 | -------------------------------------------------------------------------------- /laravel/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rossedman/aws-terraform-laravel/9794648ee2f70bef3145166cbcbdd1db163c0f51/laravel/public/favicon.ico -------------------------------------------------------------------------------- /laravel/public/index.php: -------------------------------------------------------------------------------- 1 | 8 | */ 9 | 10 | /* 11 | |-------------------------------------------------------------------------- 12 | | Register The Auto Loader 13 | |-------------------------------------------------------------------------- 14 | | 15 | | Composer provides a convenient, automatically generated class loader for 16 | | our application. We just need to utilize it! We'll simply require it 17 | | into the script here so that we don't have to worry about manual 18 | | loading any of our classes later on. It feels nice to relax. 19 | | 20 | */ 21 | 22 | require __DIR__.'/../bootstrap/autoload.php'; 23 | 24 | /* 25 | |-------------------------------------------------------------------------- 26 | | Turn On The Lights 27 | |-------------------------------------------------------------------------- 28 | | 29 | | We need to illuminate PHP development, so let us turn on the lights. 30 | | This bootstraps the framework and gets it ready for use, then it 31 | | will load up this application so that we can run it and send 32 | | the responses back to the browser and delight our users. 33 | | 34 | */ 35 | 36 | $app = require_once __DIR__.'/../bootstrap/app.php'; 37 | 38 | /* 39 | |-------------------------------------------------------------------------- 40 | | Run The Application 41 | |-------------------------------------------------------------------------- 42 | | 43 | | Once we have the application, we can handle the incoming request 44 | | through the kernel, and send the associated response back to 45 | | the client's browser allowing them to enjoy the creative 46 | | and wonderful application we have prepared for them. 47 | | 48 | */ 49 | 50 | $kernel = $app->make(Illuminate\Contracts\Http\Kernel::class); 51 | 52 | $response = $kernel->handle( 53 | $request = Illuminate\Http\Request::capture() 54 | ); 55 | 56 | $response->send(); 57 | 58 | $kernel->terminate($request, $response); 59 | -------------------------------------------------------------------------------- /laravel/public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /laravel/public/web.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /laravel/readme.md: -------------------------------------------------------------------------------- 1 | # Laravel PHP Framework 2 | 3 | [![Build Status](https://travis-ci.org/laravel/framework.svg)](https://travis-ci.org/laravel/framework) 4 | [![Total Downloads](https://poser.pugx.org/laravel/framework/d/total.svg)](https://packagist.org/packages/laravel/framework) 5 | [![Latest Stable Version](https://poser.pugx.org/laravel/framework/v/stable.svg)](https://packagist.org/packages/laravel/framework) 6 | [![Latest Unstable Version](https://poser.pugx.org/laravel/framework/v/unstable.svg)](https://packagist.org/packages/laravel/framework) 7 | [![License](https://poser.pugx.org/laravel/framework/license.svg)](https://packagist.org/packages/laravel/framework) 8 | 9 | Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable, creative experience to be truly fulfilling. Laravel attempts to take the pain out of development by easing common tasks used in the majority of web projects, such as authentication, routing, sessions, queueing, and caching. 10 | 11 | Laravel is accessible, yet powerful, providing tools needed for large, robust applications. A superb inversion of control container, expressive migration system, and tightly integrated unit testing support give you the tools you need to build any application with which you are tasked. 12 | 13 | ## Official Documentation 14 | 15 | Documentation for the framework can be found on the [Laravel website](http://laravel.com/docs). 16 | 17 | ## Contributing 18 | 19 | Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](http://laravel.com/docs/contributions). 20 | 21 | ## Security Vulnerabilities 22 | 23 | If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell at taylor@laravel.com. All security vulnerabilities will be promptly addressed. 24 | 25 | ## License 26 | 27 | The Laravel framework is open-sourced software licensed under the [MIT license](http://opensource.org/licenses/MIT). 28 | -------------------------------------------------------------------------------- /laravel/resources/assets/sass/app.scss: -------------------------------------------------------------------------------- 1 | // @import "node_modules/bootstrap-sass/assets/stylesheets/bootstrap"; 2 | 3 | -------------------------------------------------------------------------------- /laravel/resources/lang/en/auth.php: -------------------------------------------------------------------------------- 1 | 'These credentials do not match our records.', 17 | 'throttle' => 'Too many login attempts. Please try again in :seconds seconds.', 18 | 19 | ]; 20 | -------------------------------------------------------------------------------- /laravel/resources/lang/en/pagination.php: -------------------------------------------------------------------------------- 1 | '« Previous', 17 | 'next' => 'Next »', 18 | 19 | ]; 20 | -------------------------------------------------------------------------------- /laravel/resources/lang/en/passwords.php: -------------------------------------------------------------------------------- 1 | 'Passwords must be at least six characters and match the confirmation.', 17 | 'reset' => 'Your password has been reset!', 18 | 'sent' => 'We have e-mailed your password reset link!', 19 | 'token' => 'This password reset token is invalid.', 20 | 'user' => "We can't find a user with that e-mail address.", 21 | 22 | ]; 23 | -------------------------------------------------------------------------------- /laravel/resources/lang/en/validation.php: -------------------------------------------------------------------------------- 1 | 'The :attribute must be accepted.', 17 | 'active_url' => 'The :attribute is not a valid URL.', 18 | 'after' => 'The :attribute must be a date after :date.', 19 | 'alpha' => 'The :attribute may only contain letters.', 20 | 'alpha_dash' => 'The :attribute may only contain letters, numbers, and dashes.', 21 | 'alpha_num' => 'The :attribute may only contain letters and numbers.', 22 | 'array' => 'The :attribute must be an array.', 23 | 'before' => 'The :attribute must be a date before :date.', 24 | 'between' => [ 25 | 'numeric' => 'The :attribute must be between :min and :max.', 26 | 'file' => 'The :attribute must be between :min and :max kilobytes.', 27 | 'string' => 'The :attribute must be between :min and :max characters.', 28 | 'array' => 'The :attribute must have between :min and :max items.', 29 | ], 30 | 'boolean' => 'The :attribute field must be true or false.', 31 | 'confirmed' => 'The :attribute confirmation does not match.', 32 | 'date' => 'The :attribute is not a valid date.', 33 | 'date_format' => 'The :attribute does not match the format :format.', 34 | 'different' => 'The :attribute and :other must be different.', 35 | 'digits' => 'The :attribute must be :digits digits.', 36 | 'digits_between' => 'The :attribute must be between :min and :max digits.', 37 | 'dimensions' => 'The :attribute has invalid image dimensions.', 38 | 'distinct' => 'The :attribute field has a duplicate value.', 39 | 'email' => 'The :attribute must be a valid email address.', 40 | 'exists' => 'The selected :attribute is invalid.', 41 | 'filled' => 'The :attribute field is required.', 42 | 'image' => 'The :attribute must be an image.', 43 | 'in' => 'The selected :attribute is invalid.', 44 | 'in_array' => 'The :attribute field does not exist in :other.', 45 | 'integer' => 'The :attribute must be an integer.', 46 | 'ip' => 'The :attribute must be a valid IP address.', 47 | 'json' => 'The :attribute must be a valid JSON string.', 48 | 'max' => [ 49 | 'numeric' => 'The :attribute may not be greater than :max.', 50 | 'file' => 'The :attribute may not be greater than :max kilobytes.', 51 | 'string' => 'The :attribute may not be greater than :max characters.', 52 | 'array' => 'The :attribute may not have more than :max items.', 53 | ], 54 | 'mimes' => 'The :attribute must be a file of type: :values.', 55 | 'min' => [ 56 | 'numeric' => 'The :attribute must be at least :min.', 57 | 'file' => 'The :attribute must be at least :min kilobytes.', 58 | 'string' => 'The :attribute must be at least :min characters.', 59 | 'array' => 'The :attribute must have at least :min items.', 60 | ], 61 | 'not_in' => 'The selected :attribute is invalid.', 62 | 'numeric' => 'The :attribute must be a number.', 63 | 'present' => 'The :attribute field must be present.', 64 | 'regex' => 'The :attribute format is invalid.', 65 | 'required' => 'The :attribute field is required.', 66 | 'required_if' => 'The :attribute field is required when :other is :value.', 67 | 'required_unless' => 'The :attribute field is required unless :other is in :values.', 68 | 'required_with' => 'The :attribute field is required when :values is present.', 69 | 'required_with_all' => 'The :attribute field is required when :values is present.', 70 | 'required_without' => 'The :attribute field is required when :values is not present.', 71 | 'required_without_all' => 'The :attribute field is required when none of :values are present.', 72 | 'same' => 'The :attribute and :other must match.', 73 | 'size' => [ 74 | 'numeric' => 'The :attribute must be :size.', 75 | 'file' => 'The :attribute must be :size kilobytes.', 76 | 'string' => 'The :attribute must be :size characters.', 77 | 'array' => 'The :attribute must contain :size items.', 78 | ], 79 | 'string' => 'The :attribute must be a string.', 80 | 'timezone' => 'The :attribute must be a valid zone.', 81 | 'unique' => 'The :attribute has already been taken.', 82 | 'url' => 'The :attribute format is invalid.', 83 | 84 | /* 85 | |-------------------------------------------------------------------------- 86 | | Custom Validation Language Lines 87 | |-------------------------------------------------------------------------- 88 | | 89 | | Here you may specify custom validation messages for attributes using the 90 | | convention "attribute.rule" to name the lines. This makes it quick to 91 | | specify a specific custom language line for a given attribute rule. 92 | | 93 | */ 94 | 95 | 'custom' => [ 96 | 'attribute-name' => [ 97 | 'rule-name' => 'custom-message', 98 | ], 99 | ], 100 | 101 | /* 102 | |-------------------------------------------------------------------------- 103 | | Custom Validation Attributes 104 | |-------------------------------------------------------------------------- 105 | | 106 | | The following language lines are used to swap attribute place-holders 107 | | with something more reader friendly such as E-Mail Address instead 108 | | of "email". This simply helps us make messages a little cleaner. 109 | | 110 | */ 111 | 112 | 'attributes' => [], 113 | 114 | ]; 115 | -------------------------------------------------------------------------------- /laravel/resources/views/auth/emails/password.blade.php: -------------------------------------------------------------------------------- 1 | Click here to reset your password: {{ $link }} 2 | -------------------------------------------------------------------------------- /laravel/resources/views/auth/login.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 |
5 |
6 |
7 |
8 |
Login
9 |
10 |
11 | {{ csrf_field() }} 12 | 13 |
14 | 15 | 16 |
17 | 18 | 19 | @if ($errors->has('email')) 20 | 21 | {{ $errors->first('email') }} 22 | 23 | @endif 24 |
25 |
26 | 27 |
28 | 29 | 30 |
31 | 32 | 33 | @if ($errors->has('password')) 34 | 35 | {{ $errors->first('password') }} 36 | 37 | @endif 38 |
39 |
40 | 41 |
42 |
43 |
44 | 47 |
48 |
49 |
50 | 51 |
52 |
53 | 56 | 57 | Forgot Your Password? 58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | @endsection 67 | -------------------------------------------------------------------------------- /laravel/resources/views/auth/passwords/email.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | 4 | @section('content') 5 |
6 |
7 |
8 |
9 |
Reset Password
10 |
11 | @if (session('status')) 12 |
13 | {{ session('status') }} 14 |
15 | @endif 16 | 17 |
18 | {{ csrf_field() }} 19 | 20 |
21 | 22 | 23 |
24 | 25 | 26 | @if ($errors->has('email')) 27 | 28 | {{ $errors->first('email') }} 29 | 30 | @endif 31 |
32 |
33 | 34 |
35 |
36 | 39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | @endsection 48 | -------------------------------------------------------------------------------- /laravel/resources/views/auth/passwords/reset.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 |
5 |
6 |
7 |
8 |
Reset Password
9 | 10 |
11 |
12 | {{ csrf_field() }} 13 | 14 | 15 | 16 |
17 | 18 | 19 |
20 | 21 | 22 | @if ($errors->has('email')) 23 | 24 | {{ $errors->first('email') }} 25 | 26 | @endif 27 |
28 |
29 | 30 |
31 | 32 | 33 |
34 | 35 | 36 | @if ($errors->has('password')) 37 | 38 | {{ $errors->first('password') }} 39 | 40 | @endif 41 |
42 |
43 | 44 |
45 | 46 |
47 | 48 | 49 | @if ($errors->has('password_confirmation')) 50 | 51 | {{ $errors->first('password_confirmation') }} 52 | 53 | @endif 54 |
55 |
56 | 57 |
58 |
59 | 62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 | @endsection 71 | -------------------------------------------------------------------------------- /laravel/resources/views/auth/register.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 |
5 |
6 |
7 |
8 |
Register
9 |
10 |
11 | {{ csrf_field() }} 12 | 13 |
14 | 15 | 16 |
17 | 18 | 19 | @if ($errors->has('name')) 20 | 21 | {{ $errors->first('name') }} 22 | 23 | @endif 24 |
25 |
26 | 27 |
28 | 29 | 30 |
31 | 32 | 33 | @if ($errors->has('email')) 34 | 35 | {{ $errors->first('email') }} 36 | 37 | @endif 38 |
39 |
40 | 41 |
42 | 43 | 44 |
45 | 46 | 47 | @if ($errors->has('password')) 48 | 49 | {{ $errors->first('password') }} 50 | 51 | @endif 52 |
53 |
54 | 55 |
56 | 57 | 58 |
59 | 60 | 61 | @if ($errors->has('password_confirmation')) 62 | 63 | {{ $errors->first('password_confirmation') }} 64 | 65 | @endif 66 |
67 |
68 | 69 |
70 |
71 | 74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 | @endsection 83 | -------------------------------------------------------------------------------- /laravel/resources/views/emails/reminder.blade.php: -------------------------------------------------------------------------------- 1 | Hello, 2 | 3 | This is a test email from this application. 4 | -------------------------------------------------------------------------------- /laravel/resources/views/errors/503.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Be right back. 5 | 6 | 7 | 8 | 39 | 40 | 41 |
42 |
43 |
Be right back.
44 |
45 |
46 | 47 | 48 | -------------------------------------------------------------------------------- /laravel/resources/views/home.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 |
5 |
6 |
7 |
8 |
Dashboard
9 | 10 |
11 | You are logged in! 12 |
13 |
14 |
15 |
16 |
17 | @endsection 18 | -------------------------------------------------------------------------------- /laravel/resources/views/layouts/app.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Laravel 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | {{-- --}} 17 | 18 | 27 | 28 | 29 | 74 | 75 | @yield('content') 76 | 77 | 78 | 79 | 80 | {{-- --}} 81 | 82 | 83 | -------------------------------------------------------------------------------- /laravel/resources/views/test.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Laravel 5 | 6 | 7 | 8 | 37 | 38 | 39 |
40 |
41 |
This Is A Test
42 |
43 |
44 | 45 | 46 | -------------------------------------------------------------------------------- /laravel/resources/views/vendor/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /laravel/resources/views/welcome.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 |
5 |
6 |
7 |
8 |
Welcome
9 | 10 |
11 | Your Application's Landing Page. 12 |
13 |
14 |
15 |
16 |
17 | @endsection 18 | -------------------------------------------------------------------------------- /laravel/server.php: -------------------------------------------------------------------------------- 1 | 8 | */ 9 | 10 | $uri = urldecode( 11 | parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) 12 | ); 13 | 14 | // This file allows us to emulate Apache's "mod_rewrite" functionality from the 15 | // built-in PHP web server. This provides a convenient way to test a Laravel 16 | // application without having installed a "real" web server software here. 17 | if ($uri !== '/' && file_exists(__DIR__.'/public'.$uri)) { 18 | return false; 19 | } 20 | 21 | require_once __DIR__.'/public/index.php'; 22 | -------------------------------------------------------------------------------- /laravel/storage/app/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !public/ 3 | !.gitignore 4 | -------------------------------------------------------------------------------- /laravel/storage/app/public/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /laravel/storage/framework/.gitignore: -------------------------------------------------------------------------------- 1 | config.php 2 | routes.php 3 | schedule-* 4 | compiled.php 5 | services.json 6 | events.scanned.php 7 | routes.scanned.php 8 | down 9 | -------------------------------------------------------------------------------- /laravel/storage/framework/cache/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /laravel/storage/framework/sessions/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /laravel/storage/framework/views/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /laravel/storage/logs/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /laravel/tests/ExampleTest.php: -------------------------------------------------------------------------------- 1 | visit('/') 17 | ->see('Laravel 5'); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /laravel/tests/TestCase.php: -------------------------------------------------------------------------------- 1 | make(Illuminate\Contracts\Console\Kernel::class)->bootstrap(); 22 | 23 | return $app; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ssh.cfg.example: -------------------------------------------------------------------------------- 1 | Host * 2 | User ec2-user 3 | IdentityFile ./keys/private 4 | ForwardAgent yes 5 | ProxyCommand ssh -i ./keys/bastion ec2-user@ nc %h %p 6 | ServerAliveInterval 60 7 | TCPKeepAlive yes 8 | StrictHostKeyChecking no 9 | UserKnownHostsFile /dev/null 10 | VisualHostKey yes 11 | ControlMaster auto 12 | ControlPersist 5m 13 | LogLevel debug 14 | -------------------------------------------------------------------------------- /terraform/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## Deploy Code 3 | 4 | ```bash 5 | cd /to/demo/location && \ 6 | aws deploy push 7 | --application-name TestApp 8 | --s3-location s3://development.merlin.lo/TestApp 9 | --source . 10 | 11 | aws deploy create-deployment \ 12 | --application-name TestApp \ 13 | --s3-location bucket=development.merlin.lo,key=TestApp,bundleType=zip,eTag=697380dd35f4050db67983b7fc575bca,version=hr3mx4yxnWuU._Dh33n0KoOij9usqeI5 \ 14 | --deployment-group-name AutoScalingWeb \ 15 | --deployment-config-name CodeDeployDefault.OneAtATime \ 16 | --description Test Deployment 17 | ``` 18 | -------------------------------------------------------------------------------- /terraform/dns.tf: -------------------------------------------------------------------------------- 1 | 2 | /*-------------------------------------------------- 3 | * Public DNS 4 | *-------------------------------------------------*/ 5 | resource "aws_route53_record" "web" { 6 | zone_id = "${var.public_domain_zone_id}" 7 | name = "${var.public_domain}" 8 | type = "A" 9 | 10 | alias { 11 | name = "${aws_elb.web_lb.dns_name}" 12 | zone_id = "${aws_elb.web_lb.zone_id}" 13 | evaluate_target_health = true 14 | } 15 | } 16 | 17 | /*-------------------------------------------------- 18 | * Internal DNS 19 | *-------------------------------------------------*/ 20 | resource "aws_route53_record" "database" { 21 | zone_id = "${module.network.dns_zone}" 22 | name = "db.${var.internal_domain}" 23 | type = "CNAME" 24 | records = ["${aws_db_instance.mysql.address}"] 25 | ttl = 300 26 | } 27 | 28 | resource "aws_route53_record" "cache" { 29 | zone_id = "${module.network.dns_zone}" 30 | name = "cache.${var.internal_domain}" 31 | type = "CNAME" 32 | records = ["${replace(module.memcached.endpoint, "/:.*/", "")}"] 33 | ttl = 300 34 | } 35 | -------------------------------------------------------------------------------- /terraform/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | access_key = "${var.aws_access_key}" 3 | secret_key = "${var.aws_secret_key}" 4 | region = "${var.region}" 5 | } 6 | 7 | /*-------------------------------------------------- 8 | * Network 9 | * 10 | * This sets up VPC, Subnets, Internet Gateway, 11 | * Routing Tables, and more. 12 | *-------------------------------------------------*/ 13 | module "network" { 14 | source = "modules/network" 15 | 16 | azs = "${var.availability_zones}" 17 | cidr = "${var.vpc_cidr}" 18 | public_subnets = "${var.public_subnets}" 19 | private_subnets = "${var.private_subnets}" 20 | internal_domain = "${var.internal_domain}" 21 | 22 | app_name = "${var.app_name}" 23 | environment = "${var.environment}" 24 | } 25 | 26 | /*-------------------------------------------------- 27 | * Bastion 28 | * 29 | * Establish a jumphost on the public subnet perimeter 30 | * also sets ssh key for transparent jumping 31 | *-------------------------------------------------*/ 32 | module "bastion" { 33 | source = "modules/network/bastion" 34 | 35 | allowed_to_ssh = "${var.allowed_to_ssh}" 36 | ami = "${lookup(var.aws_linux_amis_ebs, var.region)}" 37 | public_key = "${var.bastion_key}" 38 | security_group_ids = "${module.network.vpc_sg}" 39 | subnet_id = "${element(split(",", module.network.public_ids), 0)}" 40 | vpc_id = "${module.network.vpc_id}" 41 | vpc_cidr = "${module.network.vpc_cidr}" 42 | 43 | app_name = "${var.app_name}" 44 | environment = "${var.environment}" 45 | } 46 | 47 | /*-------------------------------------------------- 48 | * Private Key 49 | * 50 | * Create key for private instance access 51 | *-------------------------------------------------*/ 52 | resource "aws_key_pair" "private" { 53 | key_name = "private-key" 54 | public_key = "${file(var.private_key)}" 55 | } 56 | 57 | /*-------------------------------------------------- 58 | * CodeDeploy 59 | * 60 | * Setup the deployment pipeline for the EC2 instaces 61 | *-------------------------------------------------*/ 62 | module "codedeploy" { 63 | source = "modules/codedeploy" 64 | app_name = "${var.app_name}" 65 | asg_id = "${module.asg.id}" 66 | group_name = "web" 67 | } 68 | 69 | /*-------------------------------------------------- 70 | * Load Balancer 71 | *-------------------------------------------------*/ 72 | resource "aws_elb" "web_lb" { 73 | cross_zone_load_balancing = true 74 | subnets = ["${split(",", module.network.public_ids)}"] 75 | security_groups = [ 76 | "${module.network.vpc_sg}", 77 | "${aws_security_group.web.id}" 78 | ] 79 | 80 | listener { 81 | instance_port = 80 82 | instance_protocol = "http" 83 | lb_port = 80 84 | lb_protocol = "http" 85 | } 86 | 87 | health_check { 88 | healthy_threshold = 2 89 | unhealthy_threshold = 2 90 | timeout = 3 91 | target = "HTTP:80/" 92 | interval = 60 93 | } 94 | 95 | tags { 96 | app = "${var.app_name}" 97 | env = "${var.environment}" 98 | } 99 | } 100 | 101 | /*-------------------------------------------------- 102 | * Autoscaling Group 103 | * 104 | * sets up web nodes and attaches ELB as well as 105 | * security groups and userdata 106 | *-------------------------------------------------*/ 107 | module "asg" { 108 | source = "modules/autoscaling" 109 | 110 | asg_min = 4 111 | asg_max = 8 112 | asg_cooldown = 500 113 | 114 | ec2_ami = "${lookup(var.aws_linux_amis_ebs, var.region)}" 115 | ec2_key = "${aws_key_pair.private.id}" 116 | ec2_security_groups = "${module.network.vpc_sg},${aws_security_group.web.id}" 117 | ec2_userdata_script = "scripts/userdata.sh" 118 | 119 | elb_id = "${aws_elb.web_lb.id}" 120 | private_subnets = "${module.network.private_ids}" 121 | 122 | app_name = "${var.app_name}" 123 | environment = "${var.environment}" 124 | } 125 | 126 | /*-------------------------------------------------- 127 | * Database 128 | *-------------------------------------------------*/ 129 | resource "aws_db_subnet_group" "mysql" { 130 | name = "mysql" 131 | description = "Main group of private subnets" 132 | subnet_ids = ["${split(",",module.network.private_ids)}"] 133 | 134 | tags { 135 | app_name = "${var.app_name}" 136 | environment = "${var.environment}" 137 | } 138 | } 139 | 140 | resource "aws_db_instance" "mysql" { 141 | allocated_storage = 5 142 | engine = "mysql" 143 | engine_version = "5.6.27" 144 | instance_class = "db.t2.micro" 145 | name = "${lower(var.app_name)}" 146 | username = "admin" 147 | password = "password" 148 | port = 3306 149 | multi_az = false 150 | storage_encrypted = false 151 | db_subnet_group_name = "${aws_db_subnet_group.mysql.name}" 152 | parameter_group_name = "default.mysql5.6" 153 | vpc_security_group_ids = ["${aws_security_group.database.id}"] 154 | } 155 | 156 | /*-------------------------------------------------- 157 | * Elasticache 158 | *-------------------------------------------------*/ 159 | module "memcached" { 160 | source = "modules/memcached" 161 | availability_zones = "${var.availability_zones}" 162 | private_subnets = "${module.network.private_ids}" 163 | security_groups = "${aws_security_group.cache.id}" 164 | 165 | app_name = "${var.app_name}" 166 | environment = "${var.environment}" 167 | } 168 | 169 | /*-------------------------------------------------- 170 | * SQS 171 | *-------------------------------------------------*/ 172 | resource "aws_sqs_queue" "terraform_queue" { 173 | name = "${lower(var.app_name)}-queue" 174 | } 175 | -------------------------------------------------------------------------------- /terraform/modules/autoscaling/ec2-policy.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [ 4 | { 5 | "Effect": "Allow", 6 | "Action": [ 7 | "ssm:DescribeAssociation", 8 | "ssm:GetDocument", 9 | "ssm:ListAssociations", 10 | "ssm:UpdateAssociationStatus", 11 | "ssm:UpdateInstanceInformation" 12 | ], 13 | "Resource": "*" 14 | }, 15 | { 16 | "Effect": "Allow", 17 | "Action": [ 18 | "ec2messages:AcknowledgeMessage", 19 | "ec2messages:DeleteMessage", 20 | "ec2messages:FailMessage", 21 | "ec2messages:GetEndpoint", 22 | "ec2messages:GetMessages", 23 | "ec2messages:SendReply" 24 | ], 25 | "Resource": "*" 26 | }, 27 | { 28 | "Effect": "Allow", 29 | "Action": [ 30 | "cloudwatch:PutMetricData", 31 | "cloudwatch:GetMetricStatistics", 32 | "cloudwatch:ListMetrics" 33 | ], 34 | "Resource": "*" 35 | }, 36 | { 37 | "Effect": "Allow", 38 | "Action": [ 39 | "ec2:DescribeInstanceStatus", 40 | "ec2:DescribeTags" 41 | ], 42 | "Resource": "*" 43 | }, 44 | { 45 | "Effect": "Allow", 46 | "Action": [ 47 | "ds:CreateComputer", 48 | "ds:DescribeDirectories" 49 | ], 50 | "Resource": "*" 51 | }, 52 | { 53 | "Effect": "Allow", 54 | "Action": [ 55 | "logs:CreateLogGroup", 56 | "logs:CreateLogStream", 57 | "logs:DescribeLogGroups", 58 | "logs:DescribeLogStreams", 59 | "logs:PutLogEvents" 60 | ], 61 | "Resource": "*" 62 | }, 63 | { 64 | "Effect": "Allow", 65 | "Action": [ 66 | "s3:Put*", 67 | "s3:Get*", 68 | "s3:List*", 69 | "s3:AbortMultipartUpload" 70 | ], 71 | "Resource": "*" 72 | }, 73 | { 74 | "Effect": "Allow", 75 | "Action": [ 76 | "elasticloadbalancing:Describe*", 77 | "elasticloadbalancing:DeregisterInstancesFromLoadBalancer", 78 | "elasticloadbalancing:RegisterInstancesWithLoadBalancer" 79 | ], 80 | "Resource": "*" 81 | }, 82 | { 83 | "Effect": "Allow", 84 | "Action": [ 85 | "autoscaling:Describe*", 86 | "autoscaling:EnterStandby", 87 | "autoscaling:ExitStandby", 88 | "autoscaling:UpdateAutoScalingGroup" 89 | ], 90 | "Resource": "*" 91 | }, 92 | { 93 | "Effect": "Allow", 94 | "Action": [ 95 | "sqs:SendMessage", 96 | "sqs:ReceiveMessage", 97 | "sqs:DeleteMessage", 98 | "sqs:ChangeMessageVisibility" 99 | ], 100 | "Resource": "*" 101 | }, 102 | { 103 | "Effect": "Allow", 104 | "Action": [ 105 | "ses:SendEmail", 106 | "ses:SendRawEmail" 107 | ], 108 | "Resource": "*" 109 | } 110 | ] 111 | } 112 | -------------------------------------------------------------------------------- /terraform/modules/autoscaling/ec2-role.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2008-10-17", 3 | "Statement": [ 4 | { 5 | "Sid": "", 6 | "Effect": "Allow", 7 | "Principal": { 8 | "Service": "ec2.amazonaws.com" 9 | }, 10 | "Action": "sts:AssumeRole" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /terraform/modules/autoscaling/main.tf: -------------------------------------------------------------------------------- 1 | variable "app_name" {} 2 | variable "asg_cooldown" {default = 600} 3 | variable "asg_health_check_grace_period" {default = 600} 4 | variable "asg_healthcheck_type" {default = "ELB"} 5 | variable "asg_min" {default = 2} 6 | variable "asg_max" {default = 6} 7 | variable "asg_min_elb_capacity" {default = 2} 8 | variable "asg_alarm_period" {default = 120} 9 | variable "ec2_ami" {} 10 | variable "ec2_instance_type" {default = "t2.micro"} 11 | variable "ec2_key" {} 12 | variable "ec2_security_groups" {} 13 | variable "ec2_userdata_script" {} 14 | variable "elb_id" {} 15 | variable "environment" {} 16 | variable "private_subnets" {} 17 | 18 | /*-------------------------------------------------- 19 | * Instance Role 20 | * this is a test role to see if our private instance can access S3 21 | *-------------------------------------------------*/ 22 | resource "aws_iam_role" "ec2" { 23 | name = "EC2DeployRole" 24 | assume_role_policy = "${file("${path.module}/ec2-role.json")}" 25 | } 26 | 27 | resource "aws_iam_role_policy" "ec2" { 28 | name = "EC2DeployPolicy" 29 | role = "${aws_iam_role.ec2.id}" 30 | policy = "${file("${path.module}/ec2-policy.json")}" 31 | } 32 | 33 | # can you create multiple roles and attach here? 34 | resource "aws_iam_instance_profile" "ec2" { 35 | name = "EC2DeployInstance" 36 | roles = ["${aws_iam_role.ec2.name}"] 37 | } 38 | 39 | /*-------------------------------------------------- 40 | * Launch Configuration 41 | *-------------------------------------------------*/ 42 | resource "aws_launch_configuration" "as_conf" { 43 | image_id = "${var.ec2_ami}" 44 | instance_type = "${var.ec2_instance_type}" 45 | key_name = "${var.ec2_key}" 46 | associate_public_ip_address = false 47 | iam_instance_profile = "${aws_iam_instance_profile.ec2.id}" 48 | security_groups = ["${split(",", var.ec2_security_groups)}"] 49 | user_data = "${file(var.ec2_userdata_script)}" 50 | lifecycle { create_before_destroy = true } 51 | } 52 | 53 | /*-------------------------------------------------- 54 | * Autoscaling Group 55 | *-------------------------------------------------*/ 56 | resource "aws_autoscaling_group" "web" { 57 | min_size = "${var.asg_min}" 58 | max_size = "${var.asg_max}" 59 | health_check_type = "${var.asg_healthcheck_type}" 60 | launch_configuration = "${aws_launch_configuration.as_conf.name}" 61 | load_balancers = ["${var.elb_id}"] 62 | health_check_grace_period = "${var.asg_health_check_grace_period}" 63 | #min_elb_capacity = "${var.asg_min_elb_capacity}" 64 | vpc_zone_identifier = ["${split(",", var.private_subnets)}"] 65 | 66 | tag { 67 | key = "role" 68 | value = "web" 69 | propagate_at_launch = true 70 | } 71 | 72 | tag { 73 | key = "env" 74 | value = "${var.environment}" 75 | propagate_at_launch = true 76 | } 77 | 78 | tag { 79 | key = "app" 80 | value = "${var.app_name}" 81 | propagate_at_launch = true 82 | } 83 | 84 | lifecycle { create_before_destroy = true } 85 | } 86 | 87 | /*-------------------------------------------------- 88 | * Autoscaling Policies 89 | *-------------------------------------------------*/ 90 | resource "aws_autoscaling_policy" "add_capacity" { 91 | name = "AddCapacityPolicy" 92 | scaling_adjustment = 1 93 | adjustment_type = "ChangeInCapacity" 94 | cooldown = "${var.asg_cooldown}" 95 | autoscaling_group_name = "${aws_autoscaling_group.web.name}" 96 | } 97 | 98 | resource "aws_autoscaling_policy" "remove_capacity" { 99 | name = "RemoveCapacityPolicy" 100 | scaling_adjustment = -1 101 | adjustment_type = "ChangeInCapacity" 102 | cooldown = "${var.asg_cooldown}" 103 | autoscaling_group_name = "${aws_autoscaling_group.web.name}" 104 | } 105 | 106 | /*-------------------------------------------------- 107 | * Cloudwatch Alerts For Scaling 108 | *-------------------------------------------------*/ 109 | resource "aws_cloudwatch_metric_alarm" "add_capacity" { 110 | alarm_name = "AddCapacityAlert" 111 | comparison_operator = "GreaterThanOrEqualToThreshold" 112 | evaluation_periods = "2" 113 | metric_name = "CPUUtilization" 114 | namespace = "AWS/EC2" 115 | period = "${var.asg_alarm_period}" 116 | statistic = "Average" 117 | threshold = "50" 118 | dimensions { 119 | AutoScalingGroupName = "${aws_autoscaling_group.web.name}" 120 | } 121 | alarm_description = "This metric monitor ec2 cpu utilization" 122 | alarm_actions = ["${aws_autoscaling_policy.add_capacity.arn}"] 123 | } 124 | 125 | resource "aws_cloudwatch_metric_alarm" "remove_capacity" { 126 | alarm_name = "RemoveCapacityAlert" 127 | comparison_operator = "LessThanThreshold" 128 | evaluation_periods = "2" 129 | metric_name = "CPUUtilization" 130 | namespace = "AWS/EC2" 131 | period = "${var.asg_alarm_period}" 132 | statistic = "Average" 133 | threshold = "30" 134 | dimensions { 135 | AutoScalingGroupName = "${aws_autoscaling_group.web.name}" 136 | } 137 | alarm_description = "This metric monitor ec2 cpu utilization" 138 | alarm_actions = ["${aws_autoscaling_policy.remove_capacity.arn}"] 139 | } 140 | 141 | output "id" {value = "${aws_autoscaling_group.web.id}"} 142 | -------------------------------------------------------------------------------- /terraform/modules/codedeploy/codedeploy-policy.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [ 4 | { 5 | "Effect": "Allow", 6 | "Action": [ 7 | "autoscaling:CompleteLifecycleAction", 8 | "autoscaling:DeleteLifecycleHook", 9 | "autoscaling:DescribeAutoScalingGroups", 10 | "autoscaling:DescribeLifecycleHooks", 11 | "autoscaling:PutLifecycleHook", 12 | "autoscaling:RecordLifecycleActionHeartbeat" 13 | ], 14 | "Resource": "*" 15 | }, 16 | { 17 | "Effect": "Allow", 18 | "Action": [ 19 | "ec2:DescribeInstances", 20 | "ec2:DescribeInstanceStatus" 21 | ], 22 | "Resource": "*" 23 | }, 24 | { 25 | "Effect": "Allow", 26 | "Action": [ 27 | "tag:GetTags", 28 | "tag:GetResources" 29 | ], 30 | "Resource": "*" 31 | } 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /terraform/modules/codedeploy/codedeploy-role.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [ 4 | { 5 | "Sid": "", 6 | "Effect": "Allow", 7 | "Principal": { 8 | "Service": [ 9 | "codedeploy.amazonaws.com" 10 | ] 11 | }, 12 | "Action": "sts:AssumeRole" 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /terraform/modules/codedeploy/main.tf: -------------------------------------------------------------------------------- 1 | variable "app_name" {} 2 | variable "asg_id" {} 3 | variable "group_name" {} 4 | variable "config_name" {default = "CodeDeployDefault.OneAtATime"} 5 | 6 | /*-------------------------------------------------- 7 | * Code Deploy Role 8 | *-------------------------------------------------*/ 9 | resource "aws_iam_role" "code_deploy" { 10 | name = "CodeDeployRole" 11 | assume_role_policy = "${file("${path.module}/codedeploy-role.json")}" 12 | } 13 | 14 | resource "aws_iam_role_policy" "code_deploy" { 15 | name = "CodeDeployPolicy" 16 | role = "${aws_iam_role.code_deploy.id}" 17 | policy = "${file("${path.module}/codedeploy-policy.json")}" 18 | } 19 | 20 | /*-------------------------------------------------- 21 | * Code Deploy App 22 | *-------------------------------------------------*/ 23 | resource "aws_codedeploy_app" "app" { 24 | name = "${var.app_name}" 25 | } 26 | 27 | /*-------------------------------------------------- 28 | * Code Deployment Group 29 | *-------------------------------------------------*/ 30 | resource "aws_codedeploy_deployment_group" "web" { 31 | app_name = "${aws_codedeploy_app.app.name}" 32 | deployment_group_name = "${var.group_name}" 33 | service_role_arn = "${aws_iam_role.code_deploy.arn}" 34 | autoscaling_groups = ["${var.asg_id}"] 35 | deployment_config_name = "${var.config_name}" 36 | } 37 | -------------------------------------------------------------------------------- /terraform/modules/memcached/main.tf: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------- 2 | * Variables 3 | *-------------------------------------------------*/ 4 | variable "app_name" {} 5 | variable "az_mode" {default = "cross-az"} 6 | variable "availability_zones" {} 7 | variable "environment" {} 8 | variable "maintenance_window" {default = "sun:05:00-sun:09:00"} 9 | variable "instance_type" {default = "cache.m1.small"} 10 | variable "port" {default = "11211"} 11 | variable "private_subnets" {} 12 | variable "security_groups" {} 13 | 14 | /*-------------------------------------------------- 15 | * Cache Subnet Groups 16 | *-------------------------------------------------*/ 17 | resource "aws_elasticache_subnet_group" "memcached" { 18 | name = "private-subnets" 19 | description = "Private subnet group" 20 | subnet_ids = ["${split(",", var.private_subnets)}"] 21 | } 22 | 23 | /*-------------------------------------------------- 24 | * Cache Cluster 25 | *-------------------------------------------------*/ 26 | resource "aws_elasticache_cluster" "memcached" { 27 | az_mode = "${var.az_mode}" 28 | availability_zones = ["${split(",", var.availability_zones)}"] 29 | cluster_id = "memcached-cluster" 30 | engine = "memcached" 31 | node_type = "${var.instance_type}" 32 | port = "${var.port}" 33 | maintenance_window = "${var.maintenance_window}" 34 | num_cache_nodes = "${length(compact(split(",", var.private_subnets)))}" 35 | parameter_group_name = "default.memcached1.4" 36 | security_group_ids = ["${split(",", var.security_groups)}"] 37 | subnet_group_name = "${aws_elasticache_subnet_group.memcached.name}" 38 | 39 | tags { 40 | app = "${var.app_name}" 41 | env = "${var.environment}" 42 | } 43 | } 44 | 45 | /*-------------------------------------------------- 46 | * Outputs 47 | *-------------------------------------------------*/ 48 | output "addresses" { 49 | value = "${join(",", aws_elasticache_cluster.memcached.cache_nodes.*.address)}" 50 | } 51 | 52 | output "endpoint" { 53 | value = "${aws_elasticache_cluster.memcached.configuration_endpoint}" 54 | } 55 | -------------------------------------------------------------------------------- /terraform/modules/network/bastion/main.tf: -------------------------------------------------------------------------------- 1 | variable "allowed_to_ssh" {} 2 | variable "ami" {} 3 | variable "amount" {default = "1"} 4 | variable "app_name" {} 5 | variable "environment" {} 6 | variable "instance_type" {default = "t2.micro"} 7 | variable "public_key" {} 8 | variable "security_group_ids" {default = ""} 9 | variable "subnet_id" {} 10 | variable "vpc_id" {} 11 | variable "vpc_cidr" {} 12 | 13 | /*-------------------------------------------------- 14 | * Bastion Key 15 | * create a new key for instances to use when provisioning 16 | *-------------------------------------------------*/ 17 | resource "aws_key_pair" "bastion" { 18 | key_name = "bastion-key" 19 | public_key = "${file(var.public_key)}" 20 | } 21 | 22 | /*-------------------------------------------------- 23 | * Bastion SSH 24 | * Allow SSH into the Bastion box from filtered IP addresses. 25 | * Allow SSH out only to private CIDR block. 26 | *-------------------------------------------------*/ 27 | resource "aws_security_group" "bastion" { 28 | name = "bastion" 29 | description = "Security group for bastion instances that allows SSH traffic. Allows outbound SSH to other instances in the CIDR block" 30 | vpc_id = "${var.vpc_id}" 31 | 32 | ingress { 33 | from_port = 22 34 | to_port = 22 35 | protocol = "tcp" 36 | cidr_blocks = ["${split(",", var.allowed_to_ssh)}"] 37 | } 38 | 39 | ingress { 40 | from_port = 0 41 | to_port = 0 42 | protocol = "-1" 43 | cidr_blocks = ["${var.vpc_cidr}"] 44 | } 45 | 46 | egress { 47 | from_port = 0 48 | to_port = 0 49 | protocol = "-1" 50 | cidr_blocks = ["0.0.0.0/0"] 51 | } 52 | 53 | tags { 54 | app = "${var.app_name}" 55 | env = "${var.environment}" 56 | } 57 | } 58 | 59 | /*-------------------------------------------------- 60 | * Bastion Instances 61 | * this is a normal Linux instance that we are giving access to 62 | * private boxes through the security rules. There is nothing 63 | * else being configured on this box. 64 | *-------------------------------------------------*/ 65 | resource "aws_instance" "bastion" { 66 | ami = "${var.ami}" 67 | instance_type = "${var.instance_type}" 68 | key_name = "${aws_key_pair.bastion.id}" 69 | subnet_id = "${var.subnet_id}" 70 | source_dest_check = false 71 | associate_public_ip_address = true 72 | 73 | vpc_security_group_ids = [ 74 | "${split(",", var.security_group_ids)}", 75 | "${aws_security_group.bastion.id}" 76 | ] 77 | 78 | tags { 79 | Name = "bastion" 80 | role = "bastion" 81 | app = "${var.app_name}" 82 | env = "${var.environment}" 83 | } 84 | } 85 | 86 | /*-------------------------------------------------- 87 | * Outputs 88 | *-------------------------------------------------*/ 89 | output "ip" { 90 | value = "${aws_instance.bastion.public_ip}" 91 | } 92 | -------------------------------------------------------------------------------- /terraform/modules/network/dns.tf: -------------------------------------------------------------------------------- 1 | resource "aws_route53_zone" "private" { 2 | name = "${var.internal_domain}" 3 | vpc_id = "${module.vpc.id}" 4 | } 5 | -------------------------------------------------------------------------------- /terraform/modules/network/nat/main.tf: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------- 2 | * Variables 3 | *-------------------------------------------------*/ 4 | variable "amount" {} 5 | variable "subnet_ids" {} 6 | 7 | /*-------------------------------------------------- 8 | * NAT 9 | *-------------------------------------------------*/ 10 | resource "aws_eip" "nat" { 11 | count = "${var.amount}" 12 | vpc = true 13 | } 14 | 15 | resource "aws_nat_gateway" "nat" { 16 | count = "${var.amount}" 17 | allocation_id = "${element(aws_eip.nat.*.id, count.index)}" 18 | subnet_id = "${element(split(",", var.subnet_ids), count.index)}" 19 | } 20 | 21 | /*-------------------------------------------------- 22 | * Output 23 | *-------------------------------------------------*/ 24 | output "ips" { 25 | value = "${join(",", aws_eip.nat.*.id)}" 26 | } 27 | 28 | output "ids" { 29 | value = "${join(",", aws_nat_gateway.nat.*.id)}" 30 | } 31 | -------------------------------------------------------------------------------- /terraform/modules/network/outputs.tf: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------- 2 | * Outputs 3 | *-------------------------------------------------*/ 4 | output "public_ids" {value = "${module.subnets_public.ids}"} 5 | output "private_ids" {value = "${module.subnets_private.ids}"} 6 | output "dns_zone" {value = "${aws_route53_zone.private.zone_id}"} 7 | output "vpc_id" {value = "${module.vpc.id}"} 8 | output "vpc_cidr" {value = "${module.vpc.cidr}"} 9 | output "vpc_sg" {value = "${module.vpc.sg_id}"} 10 | output "vpc_nacl_id" {value = "${module.vpc.nacl_id}"} 11 | output "vpc_gateway_id" {value = "${module.vpc.gateway_id}"} 12 | -------------------------------------------------------------------------------- /terraform/modules/network/subnet/main.tf: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------- 2 | * Variables 3 | *-------------------------------------------------*/ 4 | variable "azs" {} 5 | variable "app_name" {} 6 | variable "cidrs" {} 7 | variable "environment" {} 8 | variable "vpc_id" {} 9 | variable "public" {default = true} 10 | 11 | /*-------------------------------------------------- 12 | * Subnet 13 | *-------------------------------------------------*/ 14 | resource "aws_subnet" "mod" { 15 | count = "${length(compact(split(",", var.cidrs)))}" 16 | vpc_id = "${var.vpc_id}" 17 | cidr_block = "${element(split(",", var.cidrs), count.index)}" 18 | availability_zone = "${element(split(",", var.azs), count.index)}" 19 | map_public_ip_on_launch = "${var.public}" 20 | 21 | tags { 22 | app = "${var.app_name}" 23 | env = "${var.environment}" 24 | } 25 | } 26 | 27 | /*-------------------------------------------------- 28 | * Outputs 29 | *-------------------------------------------------*/ 30 | output "ids" { 31 | value = "${join(",",aws_subnet.mod.*.id)}" 32 | } 33 | -------------------------------------------------------------------------------- /terraform/modules/network/subnets.tf: -------------------------------------------------------------------------------- 1 | 2 | /*-------------------------------------------------- 3 | * Subnets 4 | *-------------------------------------------------*/ 5 | module "subnets_public" { 6 | source = "./subnet" 7 | azs = "${var.azs}" 8 | cidrs = "${var.public_subnets}" 9 | vpc_id = "${module.vpc.id}" 10 | public = true 11 | 12 | app_name = "${var.app_name}" 13 | environment = "${var.environment}" 14 | } 15 | 16 | module "subnets_private" { 17 | source = "./subnet" 18 | azs = "${var.azs}" 19 | cidrs = "${var.private_subnets}" 20 | vpc_id = "${module.vpc.id}" 21 | public = false 22 | 23 | app_name = "${var.app_name}" 24 | environment = "${var.environment}" 25 | } 26 | 27 | module "nat_gateways" { 28 | source = "./nat" 29 | amount = "${length(compact(split(",", var.public_subnets)))}" 30 | subnet_ids = "${module.subnets_public.ids}" 31 | } 32 | 33 | /*-------------------------------------------------- 34 | * Private Subnet Routing 35 | * route each subnet through a nat gateway 36 | *-------------------------------------------------*/ 37 | resource "aws_route_table" "private" { 38 | count = "${length(compact(split(",", var.public_subnets)))}" 39 | vpc_id = "${module.vpc.id}" 40 | 41 | route { 42 | cidr_block = "0.0.0.0/0" 43 | nat_gateway_id = "${element(split(",", module.nat_gateways.ids), count.index)}" 44 | } 45 | 46 | tags { 47 | app = "${var.app_name}" 48 | env = "${var.environment}" 49 | } 50 | } 51 | 52 | resource "aws_route_table_association" "private" { 53 | count = "${length(compact(split(",", var.private_subnets)))}" 54 | subnet_id = "${element(split(",", module.subnets_private.ids), count.index)}" 55 | route_table_id = "${element(aws_route_table.private.*.id, count.index)}" 56 | } 57 | 58 | /*-------------------------------------------------- 59 | * Public Subnet Routing 60 | * route every public subnet through internet gateway 61 | *-------------------------------------------------*/ 62 | resource "aws_route_table" "public" { 63 | vpc_id = "${module.vpc.id}" 64 | 65 | route { 66 | cidr_block = "0.0.0.0/0" 67 | gateway_id = "${module.vpc.gateway_id}" 68 | } 69 | 70 | tags { 71 | app = "${var.app_name}" 72 | env = "${var.environment}" 73 | } 74 | } 75 | 76 | resource "aws_route_table_association" "public" { 77 | count = "${length(compact(split(",", var.public_subnets)))}" 78 | subnet_id = "${element(split(",", module.subnets_public.ids), count.index)}" 79 | route_table_id = "${aws_route_table.public.id}" 80 | } 81 | -------------------------------------------------------------------------------- /terraform/modules/network/variables.tf: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------- 2 | * Variables 3 | *-------------------------------------------------*/ 4 | variable "azs" {} 5 | variable "app_name" {} 6 | variable "environment" {} 7 | variable "public_subnets" {default = ""} 8 | variable "private_subnets" {default = ""} 9 | variable "internal_domain" {} 10 | variable "cidr" {} 11 | -------------------------------------------------------------------------------- /terraform/modules/network/vpc.tf: -------------------------------------------------------------------------------- 1 | module "vpc" { 2 | source = "./vpc" 3 | cidr = "${var.cidr}" 4 | 5 | app_name = "${var.app_name}" 6 | environment = "${var.environment}" 7 | } 8 | -------------------------------------------------------------------------------- /terraform/modules/network/vpc/main.tf: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------- 2 | * Variables 3 | *-------------------------------------------------*/ 4 | variable "app_name" {} 5 | variable "cidr" {} 6 | variable "environment" {} 7 | variable "enable_dns_hostnames" {default = true} 8 | variable "enable_dns_support" {default = true} 9 | 10 | /*-------------------------------------------------- 11 | * VPC 12 | *-------------------------------------------------*/ 13 | resource "aws_vpc" "default" { 14 | cidr_block = "${var.cidr}" 15 | enable_dns_hostnames = "${var.enable_dns_hostnames}" 16 | enable_dns_support = "${var.enable_dns_support}" 17 | 18 | tags { 19 | Name = "${var.environment}-vpc" 20 | app = "${var.app_name}" 21 | env = "${var.environment}" 22 | } 23 | } 24 | 25 | /*-------------------------------------------------- 26 | * Internet Gateway 27 | *-------------------------------------------------*/ 28 | resource "aws_internet_gateway" "default" { 29 | vpc_id = "${aws_vpc.default.id}" 30 | 31 | tags { 32 | Name = "${var.environment}-internet-gateway" 33 | app = "${var.app_name}" 34 | env = "${var.environment}" 35 | } 36 | } 37 | 38 | /*-------------------------------------------------- 39 | * Outputs 40 | *-------------------------------------------------*/ 41 | output "id" {value = "${aws_vpc.default.id}"} 42 | output "cidr" {value = "${aws_vpc.default.cidr_block}"} 43 | output "sg_id" {value = "${aws_vpc.default.default_security_group_id}"} 44 | output "nacl_id" {value = "${aws_vpc.default.default_network_acl_id}"} 45 | output "gateway_id" {value = "${aws_internet_gateway.default.id}"} 46 | -------------------------------------------------------------------------------- /terraform/outputs.tf: -------------------------------------------------------------------------------- 1 | output "bastion_ip" { 2 | value = "${module.bastion.ip}" 3 | } 4 | 5 | output "address" { 6 | value = "${aws_elb.web_lb.dns_name}" 7 | } 8 | -------------------------------------------------------------------------------- /terraform/scripts/userdata.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | REGION=$(curl -s http://169.254.169.254/latest/dynamic/instance-identity/document | grep region | awk -F\" '{print $4}') 4 | 5 | # alternative JQ option 6 | # yum install -y jq 7 | # curl -s http://169.254.169.254/latest/dynamic/instance-identity/document | jq '.["region"]' -r 8 | 9 | # Install SSM Agent 10 | cd /tmp && curl https://amazon-ssm-$REGION.s3.amazonaws.com/latest/linux_amd64/amazon-ssm-agent.rpm -o amazon-ssm-agent.rpm 11 | yum install -y /tmp/amazon-ssm-agent.rpm 12 | start amazon-ssm-agent 13 | 14 | # Install CodeDeploy Agent 15 | yum install -y ruby aws-cli 16 | aws s3 cp s3://aws-codedeploy-$REGION/latest/install /home/ec2-user/install --region $REGION 17 | chmod +x /home/ec2-user/install 18 | /home/ec2-user/install auto 19 | 20 | # Install Cloudwatch Agent 21 | yum install -y perl-Switch perl-DateTime perl-Sys-Syslog perl-LWP-Protocol-https zip unzip 22 | curl http://aws-cloudwatch.s3.amazonaws.com/downloads/CloudWatchMonitoringScripts-1.2.1.zip -O 23 | unzip CloudWatchMonitoringScripts-1.2.1.zip 24 | rm CloudWatchMonitoringScripts-1.2.1.zip 25 | mv /tmp/aws-scripts-mon /root/aws-scripts-mon 26 | 27 | # Setup Cloudwatch cron for memory and disk 28 | crontab -l > mycron 29 | echo '*/5 * * * * /root/aws-scripts-mon/mon-put-instance-data.pl --mem-util --disk-space-util --disk-path=/ --from-cron' >> mycron 30 | crontab mycron 31 | rm mycron 32 | -------------------------------------------------------------------------------- /terraform/security.tf: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------- 2 | * Web Security 3 | *-------------------------------------------------*/ 4 | resource "aws_security_group" "web" { 5 | name = "http" 6 | description = "Security group for ELB" 7 | vpc_id = "${module.network.vpc_id}" 8 | 9 | ingress { 10 | from_port = 80 11 | to_port = 80 12 | protocol = "tcp" 13 | cidr_blocks = ["0.0.0.0/0"] 14 | } 15 | 16 | egress { 17 | from_port = 0 18 | to_port = 0 19 | protocol = "-1" 20 | cidr_blocks = ["0.0.0.0/0"] 21 | } 22 | 23 | tags { 24 | app = "${var.app_name}" 25 | env = "${var.environment}" 26 | } 27 | } 28 | 29 | /*-------------------------------------------------- 30 | * Database Security 31 | *-------------------------------------------------*/ 32 | resource "aws_security_group" "database" { 33 | name = "mysql" 34 | description = "Security group for MySQL" 35 | vpc_id = "${module.network.vpc_id}" 36 | 37 | ingress { 38 | from_port = 3306 39 | to_port = 3306 40 | protocol = "tcp" 41 | security_groups = ["${module.network.vpc_sg}"] 42 | } 43 | 44 | egress { 45 | from_port = 0 46 | to_port = 0 47 | protocol = "-1" 48 | security_groups = ["${module.network.vpc_sg}"] 49 | } 50 | 51 | tags { 52 | app = "${var.app_name}" 53 | env = "${var.environment}" 54 | } 55 | } 56 | 57 | /*-------------------------------------------------- 58 | * Cache Security 59 | *-------------------------------------------------*/ 60 | resource "aws_security_group" "cache" { 61 | name = "cache" 62 | description = "Security group for Memcached" 63 | vpc_id = "${module.network.vpc_id}" 64 | 65 | ingress { 66 | from_port = 11211 67 | to_port = 11211 68 | protocol = "tcp" 69 | security_groups = ["${module.network.vpc_sg}"] 70 | } 71 | 72 | egress { 73 | from_port = 0 74 | to_port = 0 75 | protocol = "-1" 76 | security_groups = ["${module.network.vpc_sg}"] 77 | } 78 | 79 | tags { 80 | app = "${var.app_name}" 81 | env = "${var.environment}" 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /terraform/terraform.tfvars: -------------------------------------------------------------------------------- 1 | # 2 | # App Specifics 3 | # This will set naming conventions for everything in AWS 4 | # 5 | app_name = "BasicApp" 6 | environment = "dev" 7 | bastion_key = "../keys/bastion.pub" 8 | private_key = "../keys/private.pub" 9 | 10 | # 11 | # Allowed To SSH 12 | # this can be a comma-separated list of cidr blocks and ip addresses 13 | # 14 | allowed_to_ssh = "76.183.238.0/24,12.25.104.0/24" 15 | 16 | # 17 | # Region & Zones 18 | # set location. make sure AZs are located in region provided 19 | # 20 | region = "us-west-2" 21 | availability_zones = "us-west-2a,us-west-2b" 22 | 23 | # 24 | # CIDR Blocks 25 | # 26 | vpc_cidr = "10.128.0.0/16" 27 | public_subnets = "10.128.10.0/24,10.128.20.0/24" 28 | private_subnets = "10.128.11.0/24,10.128.21.0/24" 29 | 30 | # 31 | # DNS 32 | # 33 | internal_domain = "rossedman.internal" 34 | public_domain = "rossedman.me" 35 | public_domain_zone_id = "Z139GCY2A7L56" 36 | -------------------------------------------------------------------------------- /terraform/variables.tf: -------------------------------------------------------------------------------- 1 | variable "aws_access_key" { 2 | description = "The AWS access key." 3 | } 4 | 5 | variable "aws_secret_key" { 6 | description = "The AWS secret key." 7 | } 8 | 9 | variable "app_name" { 10 | description = "The name of the app resources should be associated with" 11 | } 12 | 13 | variable "bastion_key" { 14 | description = "Public key for bastion host" 15 | } 16 | 17 | variable "environment" { 18 | description = "The name of the environment resources should be associated with" 19 | } 20 | 21 | variable "internal_domain" { 22 | description = "Domain used for internal DNS and private zone" 23 | } 24 | 25 | variable "private_key" { 26 | description = "The public key for private subnet instances" 27 | } 28 | 29 | variable "public_domain" { 30 | description = "Public domain that is already registered with Route53" 31 | } 32 | 33 | variable "public_domain_zone_id" { 34 | description = "Public domain zone id" 35 | } 36 | 37 | variable "region" { 38 | description = "The AWS region to create resources in." 39 | } 40 | 41 | variable "availability_zones" { 42 | description = "The availability zones" 43 | } 44 | 45 | variable "vpc_cidr" { 46 | description = "CIDR for VPC" 47 | } 48 | 49 | variable "public_subnets" { 50 | description = "comma separated cidr blocks" 51 | } 52 | 53 | variable "private_subnets" { 54 | description = "comma separated cidr blocks" 55 | } 56 | 57 | variable "allowed_to_ssh" { 58 | description = "comma separated range of CIDR blocks that will allow SSH" 59 | } 60 | 61 | # EBS backed HVM 62 | variable "aws_linux_amis_ebs" { 63 | default = { 64 | ap-northeast-1 = "ami-29160d47" 65 | ap-northeast-2 = "ami-cf32faa1" 66 | ap-southeast-1 = "ami-1ddc0b7e" 67 | ap-southeast-2 = "ami-0c95b86f" 68 | eu-central-1 = "ami-d3c022bc" 69 | eu-west-1 = "ami-b0ac25c3" 70 | sa-east-1 = "ami-fb890097" 71 | us-east-1 = "ami-f5f41398" 72 | us-west-1 = "ami-6e84fa0e" 73 | us-west-2 = "ami-d0f506b0" 74 | } 75 | } 76 | 77 | # Instance backed HVM 78 | variable "aws_linux_amis_instant" { 79 | default = { 80 | ap-northeast-1 = "ami-35110a5b" 81 | ap-northeast-2 = "ami-5430f83a" 82 | ap-southeast-1 = "ami-34dd0a57" 83 | ap-southeast-2 = "ami-e797ba84" 84 | eu-central-1 = "ami-26c12349" 85 | eu-west-1 = "ami-1aad2469" 86 | sa-east-1 = "ami-018c056d" 87 | us-east-1 = "ami-54f71039" 88 | us-west-1 = "ami-4e82fc2e" 89 | us-west-2 = "ami-3cf4075c" 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /watch: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | AWS="/usr/local/bin/aws" 4 | APPLICATION_NAME=$(git config --get aws-codedeploy.application-name) 5 | DEPLOYMENT_GROUP=$(git config --get aws-codedeploy.deployment-group) 6 | BUCKET_NAME=$(git config --get aws-codedeploy.s3bucket) 7 | BUNDLE_NAME=$(echo $(basename `pwd`).zip) 8 | LAST_DEPLOY=$($AWS deploy list-deployments --application-name $APPLICATION_NAME --deployment-group $DEPLOYMENT_GROUP | jq '.["deployments"][0]' -r) 9 | INFO=$($AWS deploy get-deployment --deployment-id $LAST_DEPLOY) 10 | echo $INFO | jq '.' 11 | --------------------------------------------------------------------------------