Repository: localstack/localstack

Issue:
bug: Error while deleting a non existent IAM policy.
### Is there an existing issue for this?

- [X] I have searched the existing issues

### Current Behavior

I got the following unexpected error when trying to delete a policy that does not exist.

```log
self = <botocore.parsers.QueryParser object at 0x7fa3d2cd2820>
xml_string = b'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">\n<title>500 Internal Server Error</title>\n<h1>Internal Serv...nd was unable to complete your request. Either the server is overloaded or there is an error in the application.</p>\n'

    def _parse_xml_string_to_dom(self, xml_string):
        try:
            parser = ETree.XMLParser(
                target=ETree.TreeBuilder(),
                encoding=self.DEFAULT_ENCODING)
            parser.feed(xml_string)
            root = parser.close()
        except XMLParseError as e:
>           raise ResponseParserError(
                "Unable to parse response (%s), "
                "invalid XML received. Further retries may succeed:\n%s" %
                (e, xml_string))
E           botocore.parsers.ResponseParserError: Unable to parse response (syntax error: line 1, column 54), invalid XML received. Further retries may succeed:
E           b'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">\n<title>500 Internal Server Error</title>\n<h1>Internal Server Error</h1>\n<p>The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.</p>\n'
```

### Expected Behavior

I expect a `ClientError` with the message code as `NoSuchEntity`

### How are you starting LocalStack?

With a `docker run` command

### Steps To Reproduce

#### How are you starting localstack (e.g., `bin/localstack` command, arguments, or `docker-compose.yml`)

`docker run --rm -it -p 4566:4566 -p 4571:4571 localstack/localstack`

#### Client commands (e.g., AWS SDK code snippet, or sequence of "awslocal" commands)

Im using boto3 with the following init:

```python
client = boto3.client(
            'iam',
            region_name="us-east-1",
            endpoint_url="http://localstack:4566",
            aws_access_key_id="dummy_id",
            aws_secret_access_key="dummy_key")
```

To reproduce the error try to delete a non existent IAM policy:

```python
import boto3
from botocore.exceptions import ClientError

client = boto3.client(
            'iam',
            region_name="us-east-1",
            endpoint_url="http://localstack:4566",
            aws_access_key_id="dummy_id",
            aws_secret_access_key="dummy_key")

try:
    client.delete_policy(PolicyArn="arn:aws:iam::000000000000:policy/non-existent-policy")
except Exception as ex:
    if isinstance(ex, ClientError):
        print("expected")
    else:
        print("not expected")
```

*Output*

```log
not expected
```

*Error*

```log
Unable to parse response (syntax error: line 1, column 54), invalid XML received. Further retries may succeed:
b'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">\n<title>500 Internal Server Error</title>\n<h1>Internal Server Error</h1>\n<p>The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.</p>\n'
```

### Environment

```markdown
- OS: MacOS BigSur 11.4
- LocalStack: latest
- Docker: v20.10.7
```


### Anything else?

_No response_


Discussion:

Resolving patch:
diff --git a/localstack/services/iam/iam_starter.py b/localstack/services/iam/iam_starter.py
--- a/localstack/services/iam/iam_starter.py
+++ b/localstack/services/iam/iam_starter.py
@@ -152,12 +152,14 @@ def iam_response_get_user(self):
 
     def iam_response_delete_policy(self):
         policy_arn = self._get_param("PolicyArn")
-        moto_iam_backend.managed_policies.pop(policy_arn, None)
-        template = self.response_template(GENERIC_EMPTY_TEMPLATE)
-        return template.render(name="DeletePolicyResponse")
+        if moto_iam_backend.managed_policies.get(policy_arn):
+            moto_iam_backend.managed_policies.pop(policy_arn, None)
+            template = self.response_template(GENERIC_EMPTY_TEMPLATE)
+            return template.render(name="DeletePolicy")
+        else:
+            raise IAMNotFoundException("Policy {0} was not found.".format(policy_arn))
 
-    if not hasattr(IamResponse, "delete_policy"):
-        IamResponse.delete_policy = iam_response_delete_policy
+    IamResponse.delete_policy = iam_response_delete_policy
 
     def iam_backend_detach_role_policy(policy_arn, role_name):
         try:


Test patch:
diff --git a/tests/integration/test_iam.py b/tests/integration/test_iam.py
--- a/tests/integration/test_iam.py
+++ b/tests/integration/test_iam.py
@@ -71,6 +71,12 @@ def test_attach_iam_role_to_new_iam_user(self):
         self.iam_client.delete_policy(PolicyArn=test_policy_arn)
         self.iam_client.delete_user(UserName=test_user_name)
 
+    def test_delete_non_existent_policy_returns_no_such_entity(self):
+        non_existent_policy_arn = "arn:aws:iam::000000000000:policy/non-existent-policy"
+        with self.assertRaises(ClientError) as ctx:
+            self.iam_client.delete_policy(PolicyArn=non_existent_policy_arn)
+        self.assertEqual("NoSuchEntity", ctx.exception.response["Error"]["Code"])
+
     def test_recreate_iam_role(self):
         role_name = "role-{}".format(short_uid())