Repository: cloud-custodian/cloud-custodian

Issue:
`aws.elastic-ip.actions.release` swallows IAM permission error?
**Describe the bug**
I created a policy to reap unused elastic IP (EIP) addresses, but I forgot to give c7n `ec2:ReleaseAddress` IAM permission. After running the policy (can be found below), it runs and doesn't throw any errors, but isn't able to release the EIP because it doesn't have the appropriate IAM permission. Shouldn't this be thrown as an error in the Lambda logs? 

**To Reproduce**
Create policy to reap unused EIP, don't give `ec2:ReleaseAddress` IAM permission, run policy

**Expected behavior**
I would expect an error to be thrown in the lambda logs, so we can capture and [report this from a lambda that captures errors](https://cloudcustodian.io/docs/aws/examples/lambdaerrorsnotify.html)

**Background (please complete the following information):**
 - OS: ubuntu 18.0.4
 - Python Version: 3.7.5
 - Custodian Version: 0.9.1
 - Tool Version: n/a
 - Cloud Provider: aws
 - Policy: [please exclude any account/sensitive information]

```yaml
vars:
  notify: &notify
    type: notify
    to:
      - slack://#c7n-alerts
    subject: "EIP - No Instances Attached - [custodian {{ account }} - {{ region }}]"
    transport:
      type: sqs
      queue: https://sqs.us-east-2.amazonaws.com/111111111/mailer
      region: us-east-2
  run_mode: &run_mode
    type: periodic
    schedule: "rate(1 day)"
    tags:
      app: "c7n"
      env: "tools"
      team: "releng"
      account: "{account_id}"
  eip_filters: &eip_filters
    - type: value
      key: InstanceId
      value: absent
    - type: value
      key: AssociationId
      value: absent

policies:
  - name: unused-eip-mark
    resource: network-addr
    description: "Mark any EIP with no instances attached for action in 7 days"
    filters:
      - "tag:maid_status_eip": absent
      - and: *eip_filters
    mode:
      <<: *run_mode
    actions:
      - type: mark-for-op
        tag: maid_status_eip
        days: 1
        op: release
      - <<: *notify
        action_desc: "Notification in 7 days if these remain orphaned"
        violation_desc: "No instances are attached to the following EIP(s)"

  - name: unused-eip-unmark-if-in-use
    resource: network-addr
    description: |
      Remove the maid_status_eip tag from any eip which has instances attached
    filters:
      - "tag:maid_status_eip": not-null
      - not: *eip_filters
    mode:
      <<: *run_mode
    actions:
      - type: remove-tag
        tags: [maid_status_eip]

  - name: unused-eip-action
    resource: network-addr
    description: "Release EIP after 7 days of having no instances"
    filters:
      - "tag:maid_status_eip": not-null
      - type: marked-for-op
        op: release
        tag: maid_status_eip
    mode:
      <<: *run_mode
    actions:
      - type: release
      - <<: *notify
        action_desc: "EIP released"
        violation_desc: "No instances are attached to EIP for over 7 days"
```

 - Traceback: [if applicable, please exclude sensitive/account information]
Lambda log:

```bash
14:04:37
START RequestId: uuid Version: $LATEST
14:04:37
[INFO] 2020-05-14T14:04:37.771Z uuid Processing event { "key1": "value1", "key2": "value2", "key3": "value3", "debug": true }
14:04:37
[DEBUG] 2020-05-14T14:04:37.771Z uuid Disabling cache
14:04:37
[WARNING] 2020-05-14T14:04:37.771Z uuid Custodian reserves policy lambda tags starting with custodian - policy specifies custodian-info
14:04:37
[DEBUG] 2020-05-14T14:04:37.773Z uuid Storing output with <LogFile file:///tmp/unused-eip-action/custodian-run.log>
14:04:37
[DEBUG] 2020-05-14T14:04:37.811Z uuid Running policy:unused-eip-action resource:network-addr region:us-east-1 c7n:0.9.1
14:04:38
[DEBUG] 2020-05-14T14:04:38.221Z uuid Filtered from 7 to 1 networkaddress
14:04:38
[INFO] 2020-05-14T14:04:38.222Z uuid policy:unused-eip-action resource:network-addr region:us-east-1 count:1 time:0.39
14:04:38
[INFO] 2020-05-14T14:04:38.343Z uuid policy:unused-eip-action action:addressrelease resources:1 execution_time:0.12
14:04:39
[INFO] 2020-05-14T14:04:39.359Z uuid sent message:b39c7995-b7f4-49b6-825e-e883678478d8 policy:unused-eip-action template:default count:1
14:04:39
[INFO] 2020-05-14T14:04:39.360Z uuid policy:unused-eip-action action:notify resources:1 execution_time:1.02
14:04:39
[DEBUG] 2020-05-14T14:04:39.360Z uuid metric:ResourceCount Count:1 policy:unused-eip-action restype:network-addr scope:policy
14:04:39
[DEBUG] 2020-05-14T14:04:39.360Z uuid metric:ApiCalls Count:4 policy:unused-eip-action restype:network-addr
14:04:39
END RequestId: uuid
14:04:39
REPORT RequestId: uuid Duration: 2323.13 ms Billed Duration: 2400 ms Memory Size: 512 MB Max Memory Used: 94 MB Init Duration: 365.90 ms
```

**Additional context**
Add any other context about the problem here.



Discussion:
yes this should be raising, it looks like a bug in the pr that added the release action  #2290 

Resolving patch:
diff --git a/c7n/resources/vpc.py b/c7n/resources/vpc.py
--- a/c7n/resources/vpc.py
+++ b/c7n/resources/vpc.py
@@ -2013,7 +2013,7 @@ def process(self, network_addrs):
                 client.release_address(AllocationId=r['AllocationId'])
             except ClientError as e:
                 # If its already been released, ignore, else raise.
-                if e.response['Error']['Code'] == 'InvalidAllocationID.NotFound':
+                if e.response['Error']['Code'] != 'InvalidAllocationID.NotFound':
                     raise
 
 


Test patch:
diff --git a/tests/test_vpc.py b/tests/test_vpc.py
--- a/tests/test_vpc.py
+++ b/tests/test_vpc.py
@@ -867,6 +867,27 @@ def test_release_detached_vpc(self):
         self.addCleanup(self.release_if_still_present, ec2, network_addr)
         self.assert_policy_released(factory, ec2, network_addr)
 
+    def test_elasticip_error(self):
+        mock_factory = MagicMock()
+        mock_factory.region = 'us-east-1'
+        mock_factory().client('ec2').release_address.side_effect = BotoClientError(
+            {'Error': {'Code': 'xyz'}},
+            operation_name='release_address')
+
+        p = self.load_policy(
+            {
+                "name": "release-network-addr",
+                "resource": "network-addr",
+                "actions": [{"type": "release", "force": False}],
+            },
+            session_factory=mock_factory,
+        )
+        with self.assertRaises(BotoClientError):
+            p.resource_manager.actions[0].process([{
+                'PublicIp': "52.207.185.218",
+                'Domain': 'Vpc',
+                'AllocationId': 'eipalloc-bbaf95b2'}])
+
     def test_elasticip_alias(self):
         try:
             self.load_policy({'name': 'eip', 'resource': 'aws.elastic-ip'}, validate=True)