In a recent investigation, we found an interesting difference between AWS command line tools (based on Boto library) and AWS Web interface. Apparently, command line tools are case sensitive while AWS Web interface is not. This can potentially lead to automated scaling issues. Tooling may not get ‘the full picture’ if tags are mixed-case and software does not account for that.
Lets start with simple example …
We have the following EC2 instances in AWS Account:

Search for the term ‘TEST-NODE’ yields the same results as searching for ‘test-node’ in the AWS Web interface.
Searching for ‘TEST-NODE':

Searching for ‘test-node':

… it behaves the same way. It is case-insensitive.
However, commend line tools will produce totally different output.
Searching for ‘TEST-NODE':
|
:~> aws ec2 describe-instances --filters "Name=tag:Name,Values=*TEST-NODE*" --query 'Reservations[*].Instances[*].Tags[?Key==`Name`].Value[]' --output text TEST-NODE-1 :~> |
Searching for ‘test-node':
|
:~> aws ec2 describe-instances --filters "Name=tag:Name,Values=*test-node*" --query 'Reservations[*].Instances[*].Tags[?Key==`Name`].Value[]' --output text test-node-5 :~> |
Python + Boto shows the same behavior (not surprisingly, AWS CLI uses Boto):
Searching for ‘TEST-NODE':
|
:~> python Python 2.7.5 (default, Mar 9 2014, 22:15:05) [GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import boto >>> import boto.ec2 >>> conn = boto.ec2.connect_to_region('us-east-1', aws_access_key_id='', aws_secret_access_key='') >>> reservations = conn.get_all_instances(filters = {'instance-state-name' : 'running', "tag:Name": "*" + 'TEST-NODE' + "*"}) >>> for r in reservations: ... for i in r.instances: ... print i.tags['Name'] ... TEST-NODE-1 >>> ^D :~> |
Searching for ‘test-node':
|
:~> python Python 2.7.5 (default, Mar 9 2014, 22:15:05) [GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import boto >>> import boto.ec2 >>> conn = boto.ec2.connect_to_region('us-east-1', aws_access_key_id='', aws_secret_access_key='') >>> reservations = conn.get_all_instances(filters = {'instance-state-name' : 'running', "tag:Name": "*" + 'test-node' + "*"}) >>> for r in reservations: ... for i in r.instances: ... print i.tags['Name'] ... test-node-5 >>> ^D :~> |
Moral of the story: ALWAYS VERIFY/ENFORCE THAT DATA IS PROPERLY FORMATTED!
There are multiple possible solutions to this issue. With the cost of few extra cycles one can make sure proper comparison is implemented:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
:~> python Python 2.7.5 (default, Mar 9 2014, 22:15:05) [GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import boto >>> import boto.ec2 >>> conn = boto.ec2.connect_to_region('us-east-1', aws_access_key_id='', aws_secret_access_key='') >>> reservations = conn.get_all_instances(filters = {'instance-state-name' : 'running'}) >>> for r in reservations: ... for i in r.instances: ... if 'test-node'.upper() in i.tags['Name'].upper(): ... print i.tags['Name'] ... TEST-NODE-1 TEST-Node-2 TEST-node-3 test-node-5 >>> ^D :~> |
References