8

I am attempting to run a few scripts while deploying using AWS Code Deploy, but they never run due to not having permissions to run the scripts.

Here is my appspec.yml file:

version: 0.0
os: linux
files:
  - source: /
    destination: /var/www/html
permissions:
  - object: /var/www/html/codedeploy-scripts
    owner: root
    mode: 777
    type:
      - directory
hooks:
  ApplicationStop:
    - location: codedeploy-scripts/application-stop
      timeout: 300
      runas: root
  BeforeInstall:
    - location: codedeploy-scripts/before-install
      timeout: 300
      runas: root
  AfterInstall:
    - location: codedeploy-scripts/after-install
      timeout: 600
      runas: root
  ApplicationStart:
    - location: codedeploy-scripts/application-start
      timeout: 300
      runas: root
  ValidateService:
    - location: codedeploy-scripts/validate-service
      timeout: 300
      runas: root

The codedeploy-scripts folder get deployed with the app and the permissions I set on the folder does not get set. The permissions on the folder always get reset to:

[ec2-user@ip-10-0-8-181 html]$ ls -al
total 156
drwxrwsr-x  7 ec2-user www   4096 Oct 13 16:36 .
drwxrwsr-x  3 ec2-user www   4096 Oct 13 15:01 ..
-rw-rw-r--  1 ec2-user www    740 Oct 13 16:28 appspec.yml
drwxr-sr-x  2 ec2-user www   4096 Oct 13 16:36 codedeploy-scripts
...

The files in the folder seem to have executable rights:

[ec2-user@ip-10-0-8-181 alio]$ ls -al codedeploy-scripts
total 28
drwxr-sr-x 2 ec2-user www 4096 Oct 13 16:36 .
drwxrwsr-x 7 ec2-user www 4096 Oct 13 16:36 ..
-rwxr-xr-x 1 ec2-user www  343 Oct 13 16:28 after-install
-rwxr-xr-x 1 ec2-user www   12 Oct 13 16:28 application-start
-rwxr-xr-x 1 ec2-user www   12 Oct 13 16:28 application-stop
-rwxr-xr-x 1 ec2-user www  889 Oct 13 16:28 before-install
-rwxr-xr-x 1 ec2-user www   12 Oct 13 16:28 validate-service

Why doesn't the code get deployed with the permissions i set in the appspec file. The codedeploy-scripts folder should have 777 permissions but it never does.

This is the error i get in /var/log/aws/codedeploy-agent/codedeploy-agent.log for each of those scripts:

2015-10-13 16:36:23 WARN  [codedeploy-agent(9918)]: InstanceAgent::Plugins::CodeDeployPlugin::HookExecutor: Script at specified location: codedeploy-scripts/validate-service is not executable.  Trying to make it executable.

Any help would be appreciated.

gprime
  • 2,283
  • 7
  • 38
  • 50

4 Answers4

6

The agent is executing the scripts directly from the extracted archive bundle not from any arbitrary places you might have copied them using the files section. You'll need to set the execute bit in your archive in S3 or Git repository.

What you have as is does this:

  • Copy all the files to /var/www/html.
  • Set permissions on the directory on the contents of /var/www/html/codedeploy-scripts to 777 but not the directory itself (See the appspec.yml reference). This will also be affected by umask, which you might be setting /etc/profile.
  • Execute each of the scripts for the lifecycle events (as they occur) from the archive root. So your ValidateSerivce script is running from <deployment-archive-root>/codedeploy-scripts/validate-service not from /var/www/html/codedeploy-scripts/validate-service

Note: ApplicationStop is special because it runs before new new archive bundle is downloaded.

Jonathan Turpie
  • 1,343
  • 10
  • 16
  • ah, yeah, setting the execute command in git fixed the issue. Thanks! – gprime Oct 14 '15 at 19:35
  • this was so non obvious... but awesome .. thank you :) – Martin Kristiansen Dec 25 '15 at 19:02
  • @gprime what do you mean by setting execute command in git? I am facing an issue which could also be related to permissions. Here it is - http://stackoverflow.com/questions/38616547/aws-codedeploy-deployment-throwing-stderr-could-not-open-input-file-at-after – Sandeepan Nath Aug 01 '16 at 06:58
  • @SandMake sure your files that need to execute have those permissions before committing to git. chmod 755 those files should do it. – gprime Aug 08 '16 at 19:36
  • 755 is totally enough..., as would be 750 if putting the -root folder to a CI group which is shared with the application user. – Florian Heigl Nov 23 '16 at 01:02
6

Without more details, I won't be able to speak to why setting your scripts to be executable fixed your issue, but the accepted answer shouldn't have resolved anything other than the log statement you were seeing.

Take a closer look at the log:

2015-10-13 16:36:23 WARN  [codedeploy-agent(9918)]: InstanceAgent::Plugins::CodeDeployPlugin::HookExecutor: Script at specified location: codedeploy-scripts/validate-service is not executable.  Trying to make it executable.

It's only a warning, not an error. The Code Deploy agent noticed that your validate_service.sh script wasn't executable and it was "Trying to make it executable". If we look at the relevant Code Deploy agent code, you'll see that the agent will chmod +x the script itself.

When you set your scripts to be executable, you only silenced this warning, and it shouldn't have affected anything else. Looking back at the Code Deploy agent code, in L106, if the agent wasn't able to make your scripts executable you would have seen an error in your logs.

To answer your question on the permissions, you have a misconfigured appspec.yml. When you say:

  permissions:
    - object: /var/www/html/codedeploy-scripts
      owner: root
      mode: 777
      type:
        - directory

You are telling Code Deploy to set all files of type "directory" within /var/www/html/codedeploy-scripts to have permissions 777.

All of your scripts under codedeploy-scripts are "file" types (not "directory"), which is why their permissions weren't set, and the permissions only apply to files under the directory you specify, which is why the permissions on the codedeploy-scripts directory weren't set.

Here's the description of the appspec.yml permission's type option from the AWS docs:

type – Optional. The types of objects to apply the specified permissions to. This can be set to file or directory. If file is specified, the permissions will be applied only to files that are immediately contained within object after the copy operation (and not to object itself). If directory is specified, the permissions will be recursively applied to all directories/folders that are anywhere within object after the copy operation (but not to object itself).

andrewkshim
  • 206
  • 3
  • 3
0

I'd like to expand on an issue mentioned by Jonathan Turpie which can create a very weird situation.

From the docs on ApplicationStop:

This deployment lifecycle event occurs even before the application revision is downloaded. ... The AppSpec file and scripts used for this deployment lifecycle event are from the previous successfully deployed application revision.

Now imagine this situation:

  1. A revision was deployed with botched ApplicationStop script permissions. The deployment still went fine because a previous version was used.
  2. A new revision is pushed and fails the ApplicationStop step (because now it tried to execute the botched script from step 1).
  3. You notice your mistake, fix the code, publish a new revision, but it still fails with the same error!

At this point it's not possible to fix the error by deploying new code. You only have two options:

  1. In the deployment settings enable "Ignore Stop failures" (e.g. with the --ignore-application-stop-failures CLI flag [1])
  2. Manually fix the file permissions in the previous successful deployment's root.

This concerns any stop script failures, not just permissions of course.

[1] https://docs.aws.amazon.com/cli/latest/reference/deploy/create-deployment.html

dskrvk
  • 1,318
  • 15
  • 24
0

Solving permission issues:

Hoping you are in the root directory where all your scripts .sh files reside:

  1. chmod +x ./*.sh

This makes all .sh files executable

  1. Add some script change_permissions.sh and add the following in the file:
#!/bin/bash
chmod -R 777 /var/www/html/

This will give your destination folder - /var/www/html/ executable permissions.

  1. Finally asspec.yml file add somehow following:
  BeforeInstall:
  - location: change_permissions.sh
    timeout: 6
    runas: root

This will at run time in your ec2 instance apply the executable permission to the files.

yogender
  • 496
  • 4
  • 7