Repository: getmoto/moto
Pull request: Support tags in Glue create_database
This PR resolves #7316.

I believe that some other taggable Glue resources are affected by the same problem. So if this PR goes into the right direction, I might add tagging-support for those resources as well.

Problem statement:
glue.create_database does not create tags
The AWS API allows to specify resource tags when creating a Glue database. However, moto will ignore those tags and not tag the database. As a demonstration, the following test fails:
```
from moto import mock_aws
import boto3

@mock_aws
def test_glue():
    database_name = "test"
    expected_tags = {"key": "value"}

    client = boto3.client("glue", region_name="eu-west-1")
    client.create_database(
        DatabaseInput={"Name": database_name, "LocationUri": "s3://somewhere"},
        Tags=expected_tags,
    )
    response = client.get_tags(ResourceArn=f"arn:aws:glue:eu-west-1:123456789012:database/{database_name}")
    assert response["Tags"] == expected_tags
```

Pytest result:
```
>       assert response["Tags"] == expected_tags
E       AssertionError: assert {} == {'key': 'value'}
E         
E         Right contains 1 more item:
E         {'key': 'value'}

glue_test.py:15: AssertionError
```

I use Moto 5.0.1.

Hints from issue discussion:

Commit message: Support tags in Glue create_database

Patch to review:
diff --git a/moto/glue/models.py b/moto/glue/models.py
index 4a8c076c1b09..ba864ec1c984 100644
--- a/moto/glue/models.py
+++ b/moto/glue/models.py
@@ -123,7 +123,10 @@ def default_vpc_endpoint_service(
         )
 
     def create_database(
-        self, database_name: str, database_input: Dict[str, Any]
+        self,
+        database_name: str,
+        database_input: Dict[str, Any],
+        tags: Optional[Dict[str, str]] = None,
     ) -> "FakeDatabase":
         if database_name in self.databases:
             raise DatabaseAlreadyExistsException()
@@ -132,6 +135,11 @@ def create_database(
             database_name, database_input, catalog_id=self.account_id
         )
         self.databases[database_name] = database
+        if tags:
+            resource_arn = f"arn:aws:glue:{self.region_name}:{self.account_id}:database/{database_name}"
+            self.tagger.tag_resource(
+                resource_arn, self.tagger.convert_dict_to_tags_input(tags)
+            )
         return database
 
     def get_database(self, database_name: str) -> "FakeDatabase":
diff --git a/moto/glue/responses.py b/moto/glue/responses.py
index f35417445f22..d5d8aad7ab43 100644
--- a/moto/glue/responses.py
+++ b/moto/glue/responses.py
@@ -24,7 +24,7 @@ def create_database(self) -> str:
         database_name = database_input.get("Name")  # type: ignore
         if "CatalogId" in self.parameters:
             database_input["CatalogId"] = self.parameters.get("CatalogId")  # type: ignore
-        self.glue_backend.create_database(database_name, database_input)  # type: ignore[arg-type]
+        self.glue_backend.create_database(database_name, database_input, self.parameters.get("Tags"))  # type: ignore[arg-type]
         return ""
 
     def get_database(self) -> str:
diff --git a/tests/test_glue/helpers.py b/tests/test_glue/helpers.py
index e900a5195f42..0ef161601e0d 100644
--- a/tests/test_glue/helpers.py
+++ b/tests/test_glue/helpers.py
@@ -19,13 +19,17 @@ def create_database_input(database_name):
     return database_input
 
 
-def create_database(client, database_name, database_input=None, catalog_id=None):
+def create_database(
+    client, database_name, database_input=None, catalog_id=None, tags=None
+):
     if database_input is None:
         database_input = create_database_input(database_name)
 
     database_kwargs = {"DatabaseInput": database_input}
     if catalog_id is not None:
         database_kwargs["CatalogId"] = catalog_id
+    if tags is not None:
+        database_kwargs["Tags"] = tags
     return client.create_database(**database_kwargs)
 
 
diff --git a/tests/test_glue/test_datacatalog.py b/tests/test_glue/test_datacatalog.py
index 739e445137d8..c3efd2c98f84 100644
--- a/tests/test_glue/test_datacatalog.py
+++ b/tests/test_glue/test_datacatalog.py
@@ -40,6 +40,23 @@ def test_create_database():
     assert database.get("CatalogId") == database_catalog_id
 
 
+@mock_aws
+def test_create_database_with_tags():
+    client = boto3.client("glue", region_name="us-east-1")
+    database_name = "myspecialdatabase"
+    database_catalog_id = ACCOUNT_ID
+    database_input = helpers.create_database_input(database_name)
+    database_tags = {"key": "value"}
+    helpers.create_database(
+        client, database_name, database_input, database_catalog_id, tags=database_tags
+    )
+
+    response = client.get_tags(
+        ResourceArn=f"arn:aws:glue:us-east-1:{ACCOUNT_ID}:database/{database_name}"
+    )
+    assert response["Tags"] == database_tags
+
+
 @mock_aws
 def test_create_database_already_exists():
     client = boto3.client("glue", region_name="us-east-1")


Code review comments:
diff_hunk: @@ -132,6 +135,11 @@ def create_database(
             database_name, database_input, catalog_id=self.account_id
         )
         self.databases[database_name] = database
+        if tags:
path: moto/glue/models.py
text: @user1:
It would be better to use `self.tag_resource(resource_arn, tags)` here.

No need for the if-statement, less code duplication, and it ensures that a call to `get_tags` always succeeds, regardless of whether the user supplied tags in the first place.

Keep in mind that you may need to change the signature of the `tag_resource` method, because the `tags`-argument then becomes `Optional`.

@author:
Thanks for your quick feedback! Using `tag_resource` is a good idea, of course. I've implemented your suggestion.