Repository: aws/aws-cli

Issue:
elasticache create-cache-cluster option '--auto-minor-version-upgrade' does not support boolean value
When trying to create an elasticache cluster in 0.12, setting the --auto-minor-version-upgrade to true or false returns Unknown options: ['true'] or Unknown options: ['false']

$ aws elasticache create-cache-cluster \
  --profile prod \
  --cache-cluster-id cachecluster-us-east-1c \
  --num-cache-nodes 1 \
  --cache-node-type cache.m1.small \
  --engine memcached \
  --engine-version 1.4.5 \
  --cache-security-group-names "lan_appservers" "lan_monitoring" \
  --preferred-availability-zone us-east-1c \
  --preferred-maintenance-window fri:08:00-fri:09:00 \
  --auto-minor-version-upgrade false

According to docs, the value is boolean, and defaults to "true". 

I had to resort to creating the cluster without the argument, let it default to true, then go change it to false in the UI.



Discussion:

Resolving patch:
diff --git a/awscli/arguments.py b/awscli/arguments.py
--- a/awscli/arguments.py
+++ b/awscli/arguments.py
@@ -187,7 +187,7 @@ def cli_type_name(self):
         if self._cli_type_name is not None:
             return self._cli_type_name
         elif self._action in ['store_true', 'store_false']:
-            cli_type_name = 'boolean'
+            return 'boolean'
         else:
             # Default to 'string' type if we don't have any
             # other info.
@@ -380,15 +380,12 @@ def __init__(self, name, argument_object, operation_object,
             self._destination = dest
 
     def add_to_params(self, parameters, value):
-        unpacked = self._unpack_argument(value)
-        if not unpacked and not self.required:
-            # Any False non-required value is just omitted
-            # from the parameter dict.  This could cause problems
-            # if there are non required parameters that default to
-            # True.
-            return
-        else:
-            parameters[self.py_name] = unpacked
+        # If a value was explicitly specified (so value is True/False
+        # but *not* None) then we add it to the params dict.
+        # If the value was not explicitly set (value is None)
+        # we don't add it to the params dict.
+        if value is not None:
+            parameters[self.py_name] = value
 
     def add_to_arg_table(self, argument_table):
         # Boolean parameters are a bit tricky.  For a single boolean parameter
@@ -409,4 +406,5 @@ def add_to_parser(self, parser):
         parser.add_argument(self.cli_name,
                             help=self.documentation,
                             action=self._action,
+                            default=None,
                             dest=self._destination)


Test patch:
diff --git a/tests/unit/elasticache/__init__.py b/tests/unit/elasticache/__init__.py
new file mode 100644
diff --git a/tests/unit/elasticache/test_create_cache_cluster.py b/tests/unit/elasticache/test_create_cache_cluster.py
new file mode 100644
--- /dev/null
+++ b/tests/unit/elasticache/test_create_cache_cluster.py
@@ -0,0 +1,94 @@
+#!/usr/bin/env python
+# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"). You
+# may not use this file except in compliance with the License. A copy of
+# the License is located at
+#
+#     http://aws.amazon.com/apache2.0/
+#
+# or in the "license" file accompanying this file. This file is
+# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
+# ANY KIND, either express or implied. See the License for the specific
+# language governing permissions and limitations under the License.
+from tests.unit import BaseAWSCommandParamsTest
+
+
+class TestCreateCacheCluster(BaseAWSCommandParamsTest):
+    maxDiff = None
+
+    prefix = 'elasticache create-cache-cluster '
+
+    def test_create_cache_cluster(self):
+        args = ('--cache-cluster-id cachecluster-us-east-1c '
+                '--num-cache-nodes 1 '
+                '--cache-node-type cache.m1.small '
+                '--engine memcached '
+                '--engine-version 1.4.5 '
+                '--cache-security-group-names group1 group2 '
+                '--preferred-availability-zone us-east-1c '
+                '--auto-minor-version-upgrade '
+                '--preferred-maintenance-window fri:08:00-fri:09:00')
+        cmdline = self.prefix + args
+        result = {'AutoMinorVersionUpgrade': 'true',
+                  'CacheClusterId': 'cachecluster-us-east-1c',
+                  'CacheNodeType': 'cache.m1.small',
+                  'CacheSecurityGroupNames.member.1': 'group1',
+                  'CacheSecurityGroupNames.member.2': 'group2',
+                  'Engine': 'memcached',
+                  'EngineVersion': '1.4.5',
+                  'NumCacheNodes': '1',
+                  'PreferredAvailabilityZone': 'us-east-1c',
+                  'PreferredMaintenanceWindow': 'fri:08:00-fri:09:00'}
+        self.assert_params_for_cmd(cmdline, result)
+
+    def test_create_cache_cluster_no_auto_minor_upgrade(self):
+        args = ('--cache-cluster-id cachecluster-us-east-1c '
+                '--num-cache-nodes 1 '
+                '--cache-node-type cache.m1.small '
+                '--engine memcached '
+                '--engine-version 1.4.5 '
+                '--cache-security-group-names group1 group2 '
+                '--preferred-availability-zone us-east-1c '
+                '--no-auto-minor-version-upgrade '
+                '--preferred-maintenance-window fri:08:00-fri:09:00')
+        cmdline = self.prefix + args
+        result = {'AutoMinorVersionUpgrade': 'false',
+                  'CacheClusterId': 'cachecluster-us-east-1c',
+                  'CacheNodeType': 'cache.m1.small',
+                  'CacheSecurityGroupNames.member.1': 'group1',
+                  'CacheSecurityGroupNames.member.2': 'group2',
+                  'Engine': 'memcached',
+                  'EngineVersion': '1.4.5',
+                  'NumCacheNodes': '1',
+                  'PreferredAvailabilityZone': 'us-east-1c',
+                  'PreferredMaintenanceWindow': 'fri:08:00-fri:09:00'}
+        self.assert_params_for_cmd(cmdline, result)
+
+    def test_minor_upgrade_arg_not_specified(self):
+        args = ('--cache-cluster-id cachecluster-us-east-1c '
+                '--num-cache-nodes 1 '
+                '--cache-node-type cache.m1.small '
+                '--engine memcached '
+                '--engine-version 1.4.5 '
+                '--cache-security-group-names group1 group2 '
+                '--preferred-availability-zone us-east-1c '
+                '--preferred-maintenance-window fri:08:00-fri:09:00')
+        cmdline = self.prefix + args
+        # Note how if neither '--auto-minor-version-upgrade' nor
+        # '--no-auto-minor-version-upgrade' is specified, then
+        # AutoMinorVersionUpgrade is not in the result dict.
+        result = {'CacheClusterId': 'cachecluster-us-east-1c',
+                  'CacheNodeType': 'cache.m1.small',
+                  'CacheSecurityGroupNames.member.1': 'group1',
+                  'CacheSecurityGroupNames.member.2': 'group2',
+                  'Engine': 'memcached',
+                  'EngineVersion': '1.4.5',
+                  'NumCacheNodes': '1',
+                  'PreferredAvailabilityZone': 'us-east-1c',
+                  'PreferredMaintenanceWindow': 'fri:08:00-fri:09:00'}
+        self.assert_params_for_cmd(cmdline, result)
+
+
+if __name__ == "__main__":
+    unittest.main()