Repository: getmoto/moto

Issue:
copy_snapshot does not write tags to destination resource
Thanks for this great library. extremely helpful to me!

```
mock = moto.mock_ec2()
mock.start()
sclient = boto3.client('ec2', region_name='us-west-2') # source client
dclient = boto3.client('ec2', region_name='us-east-1') # destination client
v_id = sclient.create_volume(AvailabilityZone='us-west-2a',
                             Size=7)['VolumeId']
snap_id = sclient.create_snapshot(
            VolumeId=v_id, TagSpecifications=snapshot_tags)['SnapshotId']
d_snap_id = dclient.copy_snapshot(
            SourceSnapshotId=snapshot_id,
            SourceRegion=source_region,
            TagSpecifications=[{'ResourceType': 'snapshot', 'Tags': spec}]
            )['SnapshotId']
dclient.describe_snapshots(SnapshotIds=[d_snap_id])
{'Snapshots': [{'Description': 'None', 'Encrypted': False, 'OwnerId': '111122223333', 'Progress': '100%', 'SnapshotId': 'snap-733b6b87', 'StartTime': datetime.datetime(2020, 4, 30, 17, 10, 52, tzinfo=tzutc()), 'State': 'completed', 'VolumeId': 'vol-00228c20', 'VolumeSize': 7, 'Tags': []}], 'ResponseMetadata': {'RequestId': '59dbff89-35bd-4eac-99ed-be587EXAMPLE', 'HTTPStatusCode': 200, 'HTTPHeaders': {'server': 'amazon.com'}, 'RetryAttempts': 0}}
```

^ notice, no tags in the destination resource

moto               1.3.14
boto3              1.12.46


Discussion:
Thanks @drewmullen - will mark this as an enhancement

Resolving patch:
diff --git a/moto/ec2/responses/elastic_block_store.py b/moto/ec2/responses/elastic_block_store.py
--- a/moto/ec2/responses/elastic_block_store.py
+++ b/moto/ec2/responses/elastic_block_store.py
@@ -19,10 +19,13 @@ def copy_snapshot(self):
         source_snapshot_id = self._get_param("SourceSnapshotId")
         source_region = self._get_param("SourceRegion")
         description = self._get_param("Description")
+        tags = self._parse_tag_specification("TagSpecification")
+        snapshot_tags = tags.get("snapshot", {})
         if self.is_not_dryrun("CopySnapshot"):
             snapshot = self.ec2_backend.copy_snapshot(
                 source_snapshot_id, source_region, description
             )
+            snapshot.add_tags(snapshot_tags)
             template = self.response_template(COPY_SNAPSHOT_RESPONSE)
             return template.render(snapshot=snapshot)
 
@@ -272,6 +275,16 @@ def reset_snapshot_attribute(self):
 COPY_SNAPSHOT_RESPONSE = """<CopySnapshotResponse xmlns="http://ec2.amazonaws.com/doc/2016-11-15/">
   <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
   <snapshotId>{{ snapshot.id }}</snapshotId>
+  <tagSet>
+    {% for tag in snapshot.get_tags() %}
+      <item>
+      <resourceId>{{ tag.resource_id }}</resourceId>
+      <resourceType>{{ tag.resource_type }}</resourceType>
+      <key>{{ tag.key }}</key>
+      <value>{{ tag.value }}</value>
+      </item>
+    {% endfor %}
+  </tagSet>
 </CopySnapshotResponse>"""
 
 DESCRIBE_SNAPSHOTS_RESPONSE = """<DescribeSnapshotsResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/">


Test patch:
diff --git a/tests/test_ec2/test_elastic_block_store.py b/tests/test_ec2/test_elastic_block_store.py
--- a/tests/test_ec2/test_elastic_block_store.py
+++ b/tests/test_ec2/test_elastic_block_store.py
@@ -9,7 +9,6 @@
 import boto3
 from botocore.exceptions import ClientError
 from boto.exception import EC2ResponseError
-from freezegun import freeze_time
 import sure  # noqa
 
 from moto import mock_ec2_deprecated, mock_ec2
@@ -834,22 +833,26 @@ def test_volume_property_hidden_when_no_tags_exist():
     volume_response.get("Tags").should.equal(None)
 
 
-@freeze_time
 @mock_ec2
 def test_copy_snapshot():
     ec2_client = boto3.client("ec2", region_name="eu-west-1")
     dest_ec2_client = boto3.client("ec2", region_name="eu-west-2")
 
     volume_response = ec2_client.create_volume(AvailabilityZone="eu-west-1a", Size=10)
+    tag_spec = [
+        {"ResourceType": "snapshot", "Tags": [{"Key": "key", "Value": "value"}]}
+    ]
 
     create_snapshot_response = ec2_client.create_snapshot(
-        VolumeId=volume_response["VolumeId"]
+        VolumeId=volume_response["VolumeId"], TagSpecifications=tag_spec
     )
 
     copy_snapshot_response = dest_ec2_client.copy_snapshot(
         SourceSnapshotId=create_snapshot_response["SnapshotId"],
         SourceRegion="eu-west-1",
+        TagSpecifications=tag_spec,
     )
+    copy_snapshot_response["Tags"].should.equal(tag_spec[0]["Tags"])
 
     ec2 = boto3.resource("ec2", region_name="eu-west-1")
     dest_ec2 = boto3.resource("ec2", region_name="eu-west-2")