Repository: getmoto/moto

Issue:
EC2 CreateTags and DeleteTags should ClientError when # of resources is 0
## Description
Moto allows the ec2 CreateTags and DeleteTags to be called with an empty list of resources. However, the AWS API returns a client error in the same scenario.

## Sample Code
```
@mock_ec2
def create_tag():
    client = boto3.client('ec2')
    client.create_tags(
        Resources=[],
        Tags=[{'Key': 'Value'}]
    )

@mock_ec2
def delete_tag():
    client = boto3.client('ec2')
    client.delete_tags(
        Resources=[],
        Tags=[{'Key': 'Value'}]
    )
```

### Expected Behaviour
Moto should return the same error as the AWS API:
```
botocore.exceptions.ClientError: An error occurred (MissingParameter) when calling the CreateTags operation: The request must contain the parameter resourceIdSet
```

```
botocore.exceptions.ClientError: An error occurred (MissingParameter) when calling the DeleteTags operation: The request must contain the parameter resourceIdSet
```

### Actual Behaviour
This succeeds:
```
create_tag()
delete_tag()
```

## Packages
```
        "moto": {
            "hashes": [
                "sha256:129de2e04cb250d9f8b2c722ec152ed1b5426ef179b4ebb03e9ec36e6eb3fcc5",
                "sha256:4df37936ff8d6a4b8229aab347a7b412cd2ca4823ff47bd1362ddfbc6c5e4ecf"
            ],
            "index": "pypi",
            "version": "==1.3.7"
        },
        "boto3": {
            "hashes": [
                "sha256:6fde6d4408d6a74a9572d88f38bf7c7eab4fa7b3599eaa5dc7fe9104f7937bb2",
                "sha256:b088a7d1da939662c6e0255e41f08e6fb43a9c7adf734a445dc5057d0a55cdf3"
            ],
            "index": "pypi",
            "version": "==1.9.105"
        },
        "botocore": {
            "hashes": [
                "sha256:2a0292d96b89657cba684be9574979abe37246a149b3591c4ff401271c446d7b",
                "sha256:fca06f04c2e6f6268045645a7a3a9c13ce7d21405eb88d2465bebf2d8e336641"
            ],
            "version": "==1.12.105"
        }
```


Discussion:

Resolving patch:
diff --git a/moto/ec2/models.py b/moto/ec2/models.py
--- a/moto/ec2/models.py
+++ b/moto/ec2/models.py
@@ -134,6 +134,8 @@ def utc_date_and_time():
 
 
 def validate_resource_ids(resource_ids):
+    if not resource_ids:
+        raise MissingParameterError(parameter='resourceIdSet')
     for resource_id in resource_ids:
         if not is_valid_resource_id(resource_id):
             raise InvalidID(resource_id=resource_id)


Test patch:
diff --git a/tests/test_ec2/test_tags.py b/tests/test_ec2/test_tags.py
--- a/tests/test_ec2/test_tags.py
+++ b/tests/test_ec2/test_tags.py
@@ -5,6 +5,7 @@
 
 import boto
 import boto3
+from botocore.exceptions import ClientError
 from boto.exception import EC2ResponseError
 from boto.ec2.instance import Reservation
 import sure  # noqa
@@ -451,3 +452,31 @@ def test_create_snapshot_with_tags():
     }]
 
     assert snapshot['Tags'] == expected_tags
+
+
+@mock_ec2
+def test_create_tag_empty_resource():
+    # create ec2 client in us-west-1
+    client = boto3.client('ec2', region_name='us-west-1')
+    # create tag with empty resource
+    with assert_raises(ClientError) as ex:
+        client.create_tags(
+            Resources=[],
+            Tags=[{'Key': 'Value'}]
+        )
+    ex.exception.response['Error']['Code'].should.equal('MissingParameter')
+    ex.exception.response['Error']['Message'].should.equal('The request must contain the parameter resourceIdSet')
+
+
+@mock_ec2
+def test_delete_tag_empty_resource():
+    # create ec2 client in us-west-1
+    client = boto3.client('ec2', region_name='us-west-1')
+    # delete tag with empty resource
+    with assert_raises(ClientError) as ex:
+        client.delete_tags(
+            Resources=[],
+            Tags=[{'Key': 'Value'}]
+        )
+    ex.exception.response['Error']['Code'].should.equal('MissingParameter')
+    ex.exception.response['Error']['Message'].should.equal('The request must contain the parameter resourceIdSet')