Repository: getmoto/moto

Issue:
elbv2 create_rule only works for one existing ALB
Hello!

This is an issue I am reporting that I hope to create my own PR to fix.

## Exception

```
botocore.errorfactory.ListenerNotFoundException: An error occurred (ListenerNotFound) when calling the CreateRule operation: The specified listener does not exist.
```

## Root Cause

In https://github.com/spulec/moto/blob/master/moto/elbv2/models.py#L549-#L551 we reuse the build in `describe_listeners`

```
     def create_rule(self, listener_arn, conditions, priority, actions):
         actions = [FakeAction(action) for action in actions]
         listeners = self.describe_listeners(None, [listener_arn])
```

Unfortunately in https://github.com/spulec/moto/blob/master/moto/elbv2/models.py#L826-#L833 we raise Exception when we encounter a different listener on an unrelated ALB.  Making it "impossible" to create a rule once two ALB's exist.

```
        matched = []
        for load_balancer in self.load_balancers.values():
            for listener_arn in listener_arns:
                listener = load_balancer.listeners.get(listener_arn)
                if not listener:
                    raise ListenerNotFoundError() # This is a problem due to aformentioned
                matched.append(listener)
        return matched
```

## Suggested Fix

```
    def describe_listeners(self, load_balancer_arn, listener_arns):
        if load_balancer_arn:
            if load_balancer_arn not in self.load_balancers:
                raise LoadBalancerNotFoundError()
            return self.load_balancers.get(load_balancer_arn).listeners.values()

        matched = []
        for load_balancer in self.load_balancers.values():
            for listener_arn in listener_arns:
                listener = load_balancer.listeners.get(listener_arn)
                if listener:
                    matched.append(listener)
        if len(matched) == 0:
            raise ListenerNotFoundError()
        return matched
```


Discussion:

Resolving patch:
diff --git a/moto/elbv2/models.py b/moto/elbv2/models.py
--- a/moto/elbv2/models.py
+++ b/moto/elbv2/models.py
@@ -827,9 +827,10 @@ def describe_listeners(self, load_balancer_arn, listener_arns):
         for load_balancer in self.load_balancers.values():
             for listener_arn in listener_arns:
                 listener = load_balancer.listeners.get(listener_arn)
-                if not listener:
-                    raise ListenerNotFoundError()
-                matched.append(listener)
+                if listener:
+                    matched.append(listener)
+        if listener_arns and len(matched) == 0:
+            raise ListenerNotFoundError()
         return matched
 
     def delete_load_balancer(self, arn):


Test patch:
diff --git a/tests/test_elbv2/test_elbv2.py b/tests/test_elbv2/test_elbv2.py
--- a/tests/test_elbv2/test_elbv2.py
+++ b/tests/test_elbv2/test_elbv2.py
@@ -415,10 +415,9 @@ def test_create_target_group_and_listeners():
     response.get("LoadBalancers").should.have.length_of(0)
 
     # And it deleted the remaining listener
-    response = conn.describe_listeners(
-        ListenerArns=[http_listener_arn, https_listener_arn]
-    )
-    response.get("Listeners").should.have.length_of(0)
+    with pytest.raises(ClientError) as e:
+        conn.describe_listeners(ListenerArns=[http_listener_arn, https_listener_arn])
+    e.value.response["Error"]["Code"].should.equal("ListenerNotFound")
 
     # But not the target groups
     response = conn.describe_target_groups()