Wednesday, April 6, 2016

How to use environment variables in Elastic Beanstalk extensions

I had this task to inject graylog collector in the Amazon instance as soon as it is deployed by Elastic Beanstalk. After some googling I found "ebextensions" (Elastic Beanstalk extensions). These are configuration files to customize the web application environment.
Below are the challenges I faced while writing ebextensions:

When does the ebextensions run and how will I know that the ebextension has run or not?
Ebextension configuration files are executed when the web application is deployed into the aws instance. Which means neither you have to rebuild the environment nor restart it. All you need is just deploy the web application which has the .ebextensions directory and all configuration yaml files. And all the logs are available in directory "/var/log/eb-activity.log" on the VM . If there are any failures or errors it should be logged into this file.

How to include hidden files in the war file using maven?
When I added ebextensions in my code and built the war I noticed that none of my configuration file are in the war. The I realized that maven war plugin does not include the hidden directory ".ebextensions" into the war file. So, I changed the pom.xml to explicitly include the ".ebextensions" along with all other files. Example is shown below:


How to read ElasticBeanstalk environment variables in the ebextenions?

Once I got the ebextensions working I wanted to read some properties from the Elastic Beanstalk configuration. From the AWS documents and some StackOverflow links I found out that environment variable and properties can be used only in "container_commands". Here I faced another problem, all of my environment variables has "." (dot) in it, example "my.prop.key" and I could not read it using the usual way. So, I had to use "printenv" to read the envirnment variable having "." (dot). Example:
container_commands:
  10_update_env_name:
    command: 'sed -i.bak "s/\"env\" = \".*\"/\"env\" = \"`printenv my.server.name`\"/g" collector.conf

After making these changes, I was able to inject environment name into the Graylog collector conf using ebextensions.

How to access OS environment variable in the ebextenions?

After injecting server name in collector conf. I had another task on installing some python modules on the AMI. So, I simply add some container commands as show below:
container_commands:
  10_install_python_pip:
    command: 'yum -y install python-pip'
  20_install_python_devel:
    command: 'yum -y install python-devel'
  30_install_libffi:
    command: 'yum -y install libffi-devel'
  40_install_openssl:
    command: 'yum -y install openssl-devel'

But, when I deploy the application then ebextensions failed with below error:
 File "/usr/lib/python2.5/UserDict.py", line 23, in __getitem__
    raise KeyError(key)
KeyError: 'PATH'


Command "python setup.py egg_info" failed with error code 1 in ...

Surprisingly, when I ran the exact command manually then it ran successfully. After scratching my head for some time and looking into the source code of "UserDict.py" I came to conclusion that for some reason ebextensions are not able to read the OS environment variable "PATH" and hence causing the error. After googling I found that OS envirnment variable are not accessible in container commands. So, I created a script and called the script from the container command and VOILA, all python modules got installed successfully. Working ebextension is as below:

files:
  "/tmp/installPython.sh":
    mode: "000755"
    owner: root
    group: root
    content: |
      #!/bin/bash

      yum -y install python-pip
      yum -y install python-devel
      yum -y install libffi-devel
      yum -y install openssl-devel

container_commands:
  10_install_python_pip:
    command: '/bin/sh /tmp/installPython.sh'



AWS Document for using ".ebextensions": http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/ebextensions.html

I hope this will be useful.

No comments:

Post a Comment