Repository: cloud-custodian/cloud-custodian

Issue:
ELB Add Tag Issue
The `add-tag` action for ELBs is failing if you have more than 1 ELB that matches the filter because of a Boto3 limitation. 

[Boto 3 Docs say:](http://boto3.readthedocs.io/en/latest/reference/services/elb.html?highlight=elb#ElasticLoadBalancing.Client.add_tags)

```
Parameters
LoadBalancerNames (list) --
[REQUIRED]

The name of the load balancer. You can specify one load balancer only.
```

Issue reported by @EricKWLee

 @EricKWLee 's Sample Policy

``` yaml
- name: delete-untagged-elb-volumes
    description: |
      Remove non-tagged elb volumes
    resource: elb
    filters:
      - or:
        - "tag:Environment": absent
    actions:
      - type: mark-for-op
        op: delete
        days: 0.01
```

@EricKWLee 's Run Log

```
2016-06-10 18:08:48,864: custodian.actions:ERROR Exception tagging resource set: [{'Value': 'Resource does not meet policy: delete@2016/06/11', 'Key': 'maid_status'}]  
 An error occurred (ValidationError) when calling the AddTags operation: Exactly 1 LoadBalancerName can be specified
2016-06-10 18:08:48,866: custodian.policy:INFO policy: delete-untagged-elb-volumes action: tagdelayedaction resources: 2 execution_time: 0.47
```

 @EricKWLee 's Error log

```
2016-06-10 12:55:15,927: custodian.actions:INFO Tagging 2 resources for delete on 2016/06/10
2016-06-10 12:55:16,426: custodian.actions:ERROR Exception tagging resource set: [
{'Value': 'Resource does not meet policy: delete@2016/06/10', 'Key': 'status'}
]
An error occurred (ValidationError) when calling the AddTags operation: Exactly 1 LoadBalancerName can be specified. ---
```



Discussion:

Resolving patch:
diff --git a/c7n/resources/elb.py b/c7n/resources/elb.py
--- a/c7n/resources/elb.py
+++ b/c7n/resources/elb.py
@@ -13,44 +13,6 @@
 # limitations under the License.
 """
 Elastic Load Balancers
-----------------------
-
-
-TODO
-####
-
-- SSL Policy enforcement
-- Empty instance waste collection
-
-Actions
-#######
-
-filters:
-  - Instances: []
-actions:
-  - type: mark-for-op
-    op: 'delete'
-    days: 7
-
-filters:
-  - type: marked-for-op
-    op: delete
-actions:
-  - delete
-
-
-Filters
-#######
-
-In addition to value filters
-
-.. code-block:: yaml
-
-  filters:
-    # Matches when the backend listener and health check are
-    # not on the same protocol
-    - healthcheck-protocol-mismatch
-
 """
 from concurrent.futures import as_completed
 import logging
@@ -110,7 +72,7 @@ class TagDelayedAction(tags.TagDelayedAction):
         'mark-for-op', rinherit=tags.TagDelayedAction.schema,
         ops={'enum': ['delete', 'set-ssl-listener-policy']})
 
-    batch_size = 20
+    batch_size = 1
 
     def process_resource_set(self, resource_set, tags):
         client = local_session(self.manager.session_factory).client('elb')
@@ -122,7 +84,7 @@ def process_resource_set(self, resource_set, tags):
 @actions.register('tag')
 class Tag(tags.Tag):
 
-    batch_size = 20
+    batch_size = 1
 
     def process_resource_set(self, resource_set, tags):
         client = local_session(
@@ -135,7 +97,7 @@ def process_resource_set(self, resource_set, tags):
 @actions.register('remove-tag')
 class RemoveTag(tags.RemoveTag):
 
-    batch_size = 20
+    batch_size = 1
 
     def process_resource_set(self, resource_set, tag_keys):
         client = local_session(
@@ -224,6 +186,7 @@ class SSLPolicyFilter(Filter):
 
     filters:
       - type: ssl-policy
+
         whitelist: []
         blacklist:
         - "Protocol-SSLv2"


Test patch: