Repository: cloud-custodian/cloud-custodian

Issue:
AppELBModifyListenerPolicy only acts on one ALB per policy run
## Issue: AppELBModifyListenerPolicy only acts on one ALB per policy run
In the `AppELBModifyListenerPolicy` class, the `process` function calls the `process_alb` function via a map concurrently but only executes the action for the first resource. The class I'm referencing is found [here](https://github.com/capitalone/cloud-custodian/blob/master/c7n/resources/appelb.py#L682-L741).

```python
    def process(self, load_balancers):
        args = {}
        if 'port' in self.data:
            args['Port'] = self.data.get('port')
        if 'protocol' in self.data:
            args['Protocol'] = self.data.get('protocol')
        if 'sslpolicy' in self.data:
            args['SslPolicy'] = self.data.get('sslpolicy')
        if 'certificate' in self.data:
            args['Certificates'] = [{'CertificateArn': self.data.get('certificate')}]
        with self.executor_factory(max_workers=2) as w:
            list(w.map(self.process_alb, load_balancers, [args]))

    def process_alb(self, alb, args):z
        client = local_session(self.manager.session_factory).client('elbv2')
        for matched_listener in alb.get('c7n:MatchedListeners', ()):
            client.modify_listener(
                ListenerArn=matched_listener['ListenerArn'],
                **args)
```

## Test:
```yaml
policies:
  - name: alb-test
    resource: app-elb
    filters:
      - type: listener
        key: Protocol
        value: HTTPS
      - type: listener
        key: SslPolicy
        value: ['ELBSecurityPolicy-TLS-1-1-2017-01','ELBSecurityPolicy-TLS-1-2-2017-01']
        op: ni
        matched: true
    actions:
      - type: modify-listener
        protocol: HTTP
        sslpolicy: "ELBSecurityPolicy-TLS-1-2-2017-01"
```

```python
    with self.executor_factory(max_workers=2) as w:
            list(w.map(self.test, load_balancers, [args]))

    def test(self, alb, args):
        log.info(alb["LoadBalancerArn"])
```
prints:
```
$ custodian run test.yml -s output
2017-10-06 14:55:37,274: custodian.policy:INFO policy: alb-test resource:app-elb region:us-east-1 count:3 time:2.39
2017-10-06 14:55:37,278: custodian.app-elb:INFO arn:aws:elasticloadbalancing:us-east-1:<account-id>:loadbalancer/app/c7n-test/123123123123123
2017-10-06 14:55:37,280: custodian.policy:INFO policy: alb-test action: appelbmodifylistenerpolicy resources: 3 execution_time: 0.00
```

## Work around:

Removing the `w.map` call to just `map` fixes this, though I would assume that would be pretty bad, as the number of concurrent API calls could be in the thousands.

```python
    list(map(self.test, load_balancers, [args]))

    def test(self, alb, args):
        log.info(alb["LoadBalancerArn"])
```
prints:
```
$ custodian run test.yml -s output
2017-10-06 14:54:03,326: custodian.policy:INFO policy: alb-test resource:app-elb region:us-east-1 count:3 time:1.52
2017-10-06 14:54:03,330: custodian.app-elb:INFO arn:aws:elasticloadbalancing:us-east-1:<account-id>:loadbalancer/app/c7n-test/123123123123123
2017-10-06 14:54:03,330: custodian.app-elb:INFO arn:aws:elasticloadbalancing:us-east-1:<account-id>:loadbalancer/app/c7n-test-2/123123123123123
2017-10-06 14:54:03,330: custodian.app-elb:INFO arn:aws:elasticloadbalancing:us-east-1:<account-id>:loadbalancer/app/c7n-test-3/123123123123123
2017-10-06 14:54:03,330: custodian.policy:INFO policy: alb-test action: appelbmodifylistenerpolicy resources: 3 execution_time: 0.00
```

Edit:

```python
    def process(self, load_balancers):
        args = {}
        if 'port' in self.data:
            args['Port'] = self.data.get('port')
        if 'protocol' in self.data:
            args['Protocol'] = self.data.get('protocol')
        if 'sslpolicy' in self.data:
            args['SslPolicy'] = self.data.get('sslpolicy')
        if 'certificate' in self.data:
            args['Certificates'] = [{'CertificateArn': self.data.get('certificate')}]
        with self.executor_factory(max_workers=2) as w:
            results = list(w.map(self.process_alb, load_balancers, [args]))
            return results

    def process_alb(self, alb, args):z
        client = local_session(self.manager.session_factory).client('elbv2')
        for matched_listener in alb.get('c7n:MatchedListeners', ()):
            client.modify_listener(
                ListenerArn=matched_listener['ListenerArn'],
                **args)
```
adding a return statement should fix it.

@alfredgamulo 


Discussion:

Resolving patch:
diff --git a/c7n/resources/appelb.py b/c7n/resources/appelb.py
--- a/c7n/resources/appelb.py
+++ b/c7n/resources/appelb.py
@@ -17,6 +17,7 @@
 from __future__ import absolute_import, division, print_function, unicode_literals
 
 import json
+import itertools
 import logging
 
 from collections import defaultdict
@@ -729,7 +730,7 @@ def process(self, load_balancers):
         if 'certificate' in self.data:
             args['Certificates'] = [{'CertificateArn': self.data.get('certificate')}]
         with self.executor_factory(max_workers=2) as w:
-            list(w.map(self.process_alb, load_balancers, [args]))
+            list(w.map(self.process_alb, load_balancers, itertools.repeat(args)))
 
     def process_alb(self, alb, args):
         client = local_session(self.manager.session_factory).client('elbv2')


Test patch: