5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ansibleのaws_rds inventory pluginが大量のClusterを取得する場合バグりそうなので、カスタムプラグインを作ってみた

Posted at

困ったこと

  • pagenationがないので、100以上クラスターがあると取得できなくなる場合が生まれる
  • describe_db_instance / describe_db_clusterのフィルターが完全一致しか対応していないので、部分一致の場合毎回全件取得しないといけない。そのためインベントリ取得のオーバヘッドが大きい
    • タグでのフィルターもできない

これを参考に↓を使ってリソースを絞り込んでからdescribe_db_instance / describe_db_clusterを実行する

はまったところ

code

  • ansible: 2.18.4
  • collection amazon.aws: 9.3.0

aws_rds_from_resource_tag.py

# -*- coding: utf-8 -*-

# Copyright (c) 2018 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
# original file is https://github.com/ansible-collections/amazon.aws/blob/9.3.0/plugins/inventory/aws_rds.py

DOCUMENTATION = r"""
name: aws_rds
short_description: RDS instance inventory source
description:
  - Get instances and clusters from Amazon Web Services RDS.
  - Uses a YAML configuration file that ends with aws_rds.(yml|yaml).
options:
  resource_tag_filters:
    description: A dictionary of filter value pairs. Available filters are listed here
        U(https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/resourcegroupstaggingapi/client/get_resources.html)
    default: {}
  regions:
    description:
      - A list of regions in which to describe RDS instances and clusters. Available regions are listed here
        U(https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.RegionsAndAvailabilityZones.html).
    default: []
  filters:
    description:
      - A dictionary of filter value pairs. Available filters are listed here
        U(https://docs.aws.amazon.com/cli/latest/reference/rds/describe-db-instances.html#options). If you filter by
        db-cluster-id and I(include_clusters) is True it will apply to clusters as well.
    default: {}
  strict_permissions:
    description:
      - By default if an AccessDenied exception is encountered this plugin will fail. You can set strict_permissions to
        False in the inventory config file which will allow the restrictions to be gracefully skipped.
    type: bool
    default: true
  include_clusters:
    description: Whether or not to query for Aurora clusters as well as instances.
    type: bool
    default: false
  statuses:
    description: A list of desired states for instances/clusters to be added to inventory. Set to ['all'] as a shorthand to find everything.
    type: list
    elements: str
    default:
      - creating
      - available
  hostvars_prefix:
    description:
      - The prefix for host variables names coming from AWS.
    type: str
    version_added: 3.1.0
  hostvars_suffix:
    description:
      - The suffix for host variables names coming from AWS.
    type: str
    version_added: 3.1.0
notes:
  - Ansible versions prior to 2.10 should use the fully qualified plugin name 'amazon.aws.aws_rds'.
extends_documentation_fragment:
  - inventory_cache
  - constructed
  - amazon.aws.boto3
  - amazon.aws.common.plugins
  - amazon.aws.region.plugins
  - amazon.aws.assume_role.plugins
author:
  - Sloane Hertel (@s-hertel)
"""

EXAMPLES = r"""
plugin: aws_rds
regions:
  - us-east-1
  - ca-central-1
resource_tag_filters:
  EnvironmentName: dummy-develop
keyed_groups:
  - key: 'db_parameter_groups|json_query("[].db_parameter_group_name")'
    prefix: rds_parameter_group
  - key: engine
    prefix: rds
  - key: tags
  - key: region
hostvars_prefix: aws_
hostvars_suffix: _rds
"""

try:
    import botocore
except ImportError:
    pass  # will be captured by imported HAS_BOTO3

from ansible.errors import AnsibleError
from ansible.module_utils._text import to_native
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict

from ansible.module_utils.six import integer_types
from ansible.module_utils.six import string_types

from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
from ansible_collections.amazon.aws.plugins.module_utils.transformation import ansible_dict_to_boto3_filter_list
from ansible_collections.amazon.aws.plugins.plugin_utils.inventory import AWSInventoryBase


def _find_hosts_with_valid_statuses(hosts, statuses):
    if "all" in statuses:
        return hosts
    valid_hosts = []
    for host in hosts:
        if host.get("DBInstanceStatus") in statuses:
            valid_hosts.append(host)
        elif host.get("Status") in statuses:
            valid_hosts.append(host)
    return valid_hosts


def _get_rds_hostname(host):
    if host.get("DBInstanceIdentifier"):
        return host["DBInstanceIdentifier"]
    else:
        return host["DBClusterIdentifier"]


def _add_tags_for_rds_hosts(connection, hosts, strict):
    for host in hosts:
        if "DBInstanceArn" in host:
            resource_arn = host["DBInstanceArn"]
        else:
            resource_arn = host["DBClusterArn"]

        try:
            tags = connection.list_tags_for_resource(ResourceName=resource_arn)["TagList"]
        except is_boto3_error_code("AccessDenied") as e:
            if not strict:
                tags = []
            else:
                raise e
        host["Tags"] = tags


def describe_resource_with_tags(func):
    def describe_wrapper(connection, filters, strict=False):
        try:
            results = func(connection=connection, filters=filters)
            if "DBInstances" in results:
                results = results["DBInstances"]
            else:
                results = results["DBClusters"]
            _add_tags_for_rds_hosts(connection, results, strict)
        except is_boto3_error_code("AccessDenied") as e:  # pylint: disable=duplicate-except
            if not strict:
                return []
            raise AnsibleError(f"Failed to query RDS: {to_native(e)}")
        except (
            botocore.exceptions.BotoCoreError,
            botocore.exceptions.ClientError,
        ) as e:  # pylint: disable=duplicate-except
            raise AnsibleError(f"Failed to query RDS: {to_native(e)}")

        return results

    return describe_wrapper


@describe_resource_with_tags
def _describe_db_instances(connection, filters):
    paginator = connection.get_paginator("describe_db_instances")
    return paginator.paginate(Filters=filters).build_full_result()


@describe_resource_with_tags
def _describe_db_clusters(connection, filters):
    return connection.describe_db_clusters(Filters=filters)


class InventoryModule(AWSInventoryBase):
    NAME = "custom.aws_rds_from_resource_tag"  # forked from amazon.aws.aws_rds
    INVENTORY_FILE_SUFFIXES = (
        "aws_rds_from_resource_tag.yml",
        "aws_rds_from_resource_tag.yaml",
    )

    def __init__(self):
        super().__init__()
        self.credentials = {}

    def _populate(self, hosts):
        group = "aws_rds"
        self.inventory.add_group(group)
        if hosts:
            self._add_hosts(hosts=hosts, group=group)
            self.inventory.add_child("all", group)

    def _populate_from_source(self, source_data):
        hostvars = source_data.pop("_meta", {}).get("hostvars", {})
        for group in source_data:
            if group == "all":
                continue
            self.inventory.add_group(group)
            hosts = source_data[group].get("hosts", [])
            for host in hosts:
                self._populate_host_vars([host], hostvars.get(host, {}), group)
            self.inventory.add_child("all", group)

    def _format_inventory(self, hosts):
        results = {"_meta": {"hostvars": {}}}
        group = "aws_rds"
        results[group] = {"hosts": []}
        for host in hosts:
            hostname = _get_rds_hostname(host)
            results[group]["hosts"].append(hostname)
            h = self.inventory.get_host(hostname)
            results["_meta"]["hostvars"][h.name] = h.vars
        return results

    def _update_filters(self, filters, filter_name, value):
        if [d for d in filters if d['Name'] == filter_name]:
            filters = [
                {"Name": d["Name"], "Values": list(set(d["Values"] + value))} if d['Name'] == filter_name else d for d in filters
            ]
        else:
            filters += [{"Name": filter_name, "Values": value}]
        return filters

    def _ansible_dict_to_boto3_resourcegroupstaggingapi_filter_list(self, filters_dict):
        """Convert an Ansible dict of filters to list of dicts that boto3 resourcegroupstaggingapi.get_resources can use
        https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/resourcegroupstaggingapi/client/get_resources.html
        Args:
            filters_dict (dict): Dict of AWS filters.
        Basic Usage:
            >>> filters = {'some-aws-id': 'i-01234567'}
            >>> ansible_dict_to_boto3_filter_list(filters)
            {
                'some-aws-id': 'i-01234567'
            }
        Returns:
            List: List of AWS filters and their values
            [
                {
                    'Key': 'some-aws-id',
                    'Values': [
                        'i-01234567',
                    ]
                }
            ]
        """

        filters_list = []
        for k, v in filters_dict.items():
            filter_dict = {"Key": k}
            if isinstance(v, bool):
                filter_dict["Values"] = [str(v).lower()]
            elif isinstance(v, integer_types):
                filter_dict["Values"] = [str(v)]
            elif isinstance(v, string_types):
                filter_dict["Values"] = [v]
            else:
                filter_dict["Values"] = v

            filters_list.append(filter_dict)

        return filters_list

    def _add_hosts(self, hosts, group):
        """
        :param hosts: a list of hosts to be added to a group
        :param group: the name of the group to which the hosts belong
        """
        for host in hosts:
            hostname = _get_rds_hostname(host)
            host = camel_dict_to_snake_dict(host, ignore_list=["Tags"])
            host["tags"] = boto3_tag_list_to_ansible_dict(host.get("tags", []))

            # Allow easier grouping by region
            if "availability_zone" in host:
                host["region"] = host["availability_zone"][:-1]
            elif "availability_zones" in host:
                host["region"] = host["availability_zones"][0][:-1]

            self.inventory.add_host(hostname, group=group)
            hostvars_prefix = self.get_option("hostvars_prefix")
            hostvars_suffix = self.get_option("hostvars_suffix")
            new_vars = dict()
            for hostvar, hostval in host.items():
                if hostvars_prefix:
                    hostvar = hostvars_prefix + hostvar
                if hostvars_suffix:
                    hostvar = hostvar + hostvars_suffix
                new_vars[hostvar] = hostval
                self.inventory.set_variable(hostname, hostvar, hostval)
            host.update(new_vars)

            # Use constructed if applicable
            strict = self.get_option("strict")
            # Composed variables
            self._set_composite_vars(self.get_option("compose"), host, hostname, strict=strict)
            # Complex groups based on jinja2 conditionals, hosts that meet the conditional are added to group
            self._add_host_to_composed_groups(self.get_option("groups"), host, hostname, strict=strict)
            # Create groups based on variable values and add the corresponding hosts to it
            self._add_host_to_keyed_groups(self.get_option("keyed_groups"), host, hostname, strict=strict)

    def _get_all_db_hosts(self, regions, tag_filters, instance_filters, cluster_filters, strict, statuses, gather_clusters=False):
        """
        :param regions: a list of regions in which to describe hosts
        :param tag_filters: a list of boto3 filter dictionaries
        :param instance_filters: a list of boto3 filter dictionaries
        :param cluster_filters: a list of boto3 filter dictionaries
        :param strict: a boolean determining whether to fail or ignore 403 error codes
        :param statuses: a list of statuses that the returned hosts should match
        :return A list of host dictionaries
        """
        all_instances = []
        all_clusters = []

        for connection, _region in self.all_clients("rds"):
            resourcegroupstaggingapi = self.client(
                'resourcegroupstaggingapi', region=_region
            )
            resource_tag_mapping_list_instances = (
                resourcegroupstaggingapi.get_resources(
                    TagFilters=tag_filters, ResourceTypeFilters=["rds:db"]
                )["ResourceTagMappingList"]
            )
            # Put an empty list in db-instance-id in filters to get InvalidParameterCombination. So, put the dummy value by default.
            instances = ["DummyForAvoidInvalidParameterCombination"] + [
                i["ResourceARN"].split(":")[-1]
                for i in resource_tag_mapping_list_instances
            ]
            instance_filters = self._update_filters(
                instance_filters, "db-instance-id", instances
            )
            all_instances += _describe_db_instances(connection, instance_filters, strict=strict)
            if gather_clusters:
                resource_tag_mapping_list_clusters = (
                    resourcegroupstaggingapi.get_resources(
                        TagFilters=tag_filters, ResourceTypeFilters=["rds:cluster"]
                    )["ResourceTagMappingList"]
                )
                # Put an empty list in db-cluster-id in filters to get InvalidParameterCombination. So, put the dummy value by default.
                clusters = ["DummyForAvoidInvalidParameterCombination"] + [
                    i["ResourceARN"].split(":")[-1]
                    for i in resource_tag_mapping_list_clusters
                ]
                cluster_filters = self._update_filters(
                    cluster_filters, "db-cluster-id", clusters
                )
                all_clusters += _describe_db_clusters(connection, cluster_filters, strict=strict)
        sorted_hosts = list(
            sorted(all_instances, key=lambda x: x["DBInstanceIdentifier"])
            + sorted(all_clusters, key=lambda x: x["DBClusterIdentifier"])
        )
        return _find_hosts_with_valid_statuses(sorted_hosts, statuses)

    def parse(self, inventory, loader, path, cache=True):
        super().parse(inventory, loader, path, cache=cache)

        # get user specifications
        regions = self.get_option("regions")
        filters = self.get_option("filters")
        resource_tag_filters = self.get_option("resource_tag_filters")
        strict_permissions = self.get_option("strict_permissions")
        statuses = self.get_option("statuses")
        include_clusters = self.get_option("include_clusters")
        instance_filters = ansible_dict_to_boto3_filter_list(filters)
        tag_filters = self._ansible_dict_to_boto3_resourcegroupstaggingapi_filter_list(
            resource_tag_filters
        )
        cluster_filters = []
        if "db-cluster-id" in filters and include_clusters:
            cluster_filters = ansible_dict_to_boto3_filter_list({"db-cluster-id": filters["db-cluster-id"]})

        result_was_cached, cached_result = self.get_cached_result(path, cache)
        if result_was_cached:
            self._populate_from_source(cached_result)
            return

        results = self._get_all_db_hosts(
            regions,
            tag_filters,
            instance_filters,
            cluster_filters,
            strict_permissions,
            statuses,
            include_clusters,
        )
        self._populate(results)

        # Update the cache once we're done
        formatted_inventory = self._format_inventory(results)
        self.update_cached_result(path, cache, formatted_inventory)

元のコードとの差分

diff aws_rds.py aws_rds_from_resource_tag.py の結果

4a5
> # original file is https://github.com/ansible-collections/amazon.aws/blob/9.3.0/plugins/inventory/aws_rds.py
12a14,17
>   resource_tag_filters:
>     description: A dictionary of filter value pairs. Available filters are listed here
>         U(https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/resourcegroupstaggingapi/client/get_resources.html)
>     default: {}
68a74,75
> resource_tag_filters:
>   EnvironmentName: dummy-develop
89,100c96,102
< from ansible_collections.amazon.aws.plugins.module_utils.botocore import (
<     is_boto3_error_code,
< )
< from ansible_collections.amazon.aws.plugins.module_utils.tagging import (
<     boto3_tag_list_to_ansible_dict,
< )
< from ansible_collections.amazon.aws.plugins.module_utils.transformation import (
<     ansible_dict_to_boto3_filter_list,
< )
< from ansible_collections.amazon.aws.plugins.plugin_utils.inventory import (
<     AWSInventoryBase,
< )
---
> from ansible.module_utils.six import integer_types
> from ansible.module_utils.six import string_types
> 
> from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
> from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict
> from ansible_collections.amazon.aws.plugins.module_utils.transformation import ansible_dict_to_boto3_filter_list
> from ansible_collections.amazon.aws.plugins.plugin_utils.inventory import AWSInventoryBase
130,132c132
<             tags = connection.list_tags_for_resource(ResourceName=resource_arn)[
<                 "TagList"
<             ]
---
>             tags = connection.list_tags_for_resource(ResourceName=resource_arn)["TagList"]
150,152c150
<         except is_boto3_error_code(
<             "AccessDenied"
<         ) as e:  # pylint: disable=duplicate-except
---
>         except is_boto3_error_code("AccessDenied") as e:  # pylint: disable=duplicate-except
179,180c177,181
<     NAME = "amazon.aws.aws_rds"
<     INVENTORY_FILE_SUFFIXES = ("aws_rds.yml", "aws_rds.yaml")
---
>     NAME = "custom.aws_rds_from_resource_tag"  # forked from amazon.aws.aws_rds
>     INVENTORY_FILE_SUFFIXES = (
>         "aws_rds_from_resource_tag.yml",
>         "aws_rds_from_resource_tag.yaml",
>     )
214a216,263
>     def _update_filters(self, filters, filter_name, value):
>         if [d for d in filters if d['Name'] == filter_name]:
>             filters = [
>                 {"Name": d["Name"], "Values": list(set(d["Values"] + value))} if d['Name'] == filter_name else d for d in filters
>             ]
>         else:
>             filters += [{"Name": filter_name, "Values": value}]
>         return filters
> 
>     def _ansible_dict_to_boto3_resourcegroupstaggingapi_filter_list(self, filters_dict):
>         """Convert an Ansible dict of filters to list of dicts that boto3 resourcegroupstaggingapi.get_resources can use
>         https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/resourcegroupstaggingapi/client/get_resources.html
>         Args:
>             filters_dict (dict): Dict of AWS filters.
>         Basic Usage:
>             >>> filters = {'some-aws-id': 'i-01234567'}
>             >>> ansible_dict_to_boto3_filter_list(filters)
>             {
>                 'some-aws-id': 'i-01234567'
>             }
>         Returns:
>             List: List of AWS filters and their values
>             [
>                 {
>                     'Key': 'some-aws-id',
>                     'Values': [
>                         'i-01234567',
>                     ]
>                 }
>             ]
>         """
> 
>         filters_list = []
>         for k, v in filters_dict.items():
>             filter_dict = {"Key": k}
>             if isinstance(v, bool):
>                 filter_dict["Values"] = [str(v).lower()]
>             elif isinstance(v, integer_types):
>                 filter_dict["Values"] = [str(v)]
>             elif isinstance(v, string_types):
>                 filter_dict["Values"] = [v]
>             else:
>                 filter_dict["Values"] = v
> 
>             filters_list.append(filter_dict)
> 
>         return filters_list
> 
247,249c296
<             self._set_composite_vars(
<                 self.get_option("compose"), host, hostname, strict=strict
<             )
---
>             self._set_composite_vars(self.get_option("compose"), host, hostname, strict=strict)
251,253c298
<             self._add_host_to_composed_groups(
<                 self.get_option("groups"), host, hostname, strict=strict
<             )
---
>             self._add_host_to_composed_groups(self.get_option("groups"), host, hostname, strict=strict)
255,257c300
<             self._add_host_to_keyed_groups(
<                 self.get_option("keyed_groups"), host, hostname, strict=strict
<             )
---
>             self._add_host_to_keyed_groups(self.get_option("keyed_groups"), host, hostname, strict=strict)
259,267c302
<     def _get_all_db_hosts(
<         self,
<         regions,
<         instance_filters,
<         cluster_filters,
<         strict,
<         statuses,
<         gather_clusters=False,
<     ):
---
>     def _get_all_db_hosts(self, regions, tag_filters, instance_filters, cluster_filters, strict, statuses, gather_clusters=False):
269a305
>         :param tag_filters: a list of boto3 filter dictionaries
280,281c316,322
<             all_instances += _describe_db_instances(
<                 connection, instance_filters, strict=strict
---
>             resourcegroupstaggingapi = self.client(
>                 'resourcegroupstaggingapi', region=_region
>             )
>             resource_tag_mapping_list_instances = (
>                 resourcegroupstaggingapi.get_resources(
>                     TagFilters=tag_filters, ResourceTypeFilters=["rds:db"]
>                 )["ResourceTagMappingList"]
282a324,332
>             # Put an empty list in db-instance-id in filters to get InvalidParameterCombination. So, put the dummy value by default.
>             instances = ["DummyForAvoidInvalidParameterCombination"] + [
>                 i["ResourceARN"].split(":")[-1]
>                 for i in resource_tag_mapping_list_instances
>             ]
>             instance_filters = self._update_filters(
>                 instance_filters, "db-instance-id", instances
>             )
>             all_instances += _describe_db_instances(connection, instance_filters, strict=strict)
284,285c334,345
<                 all_clusters += _describe_db_clusters(
<                     connection, cluster_filters, strict=strict
---
>                 resource_tag_mapping_list_clusters = (
>                     resourcegroupstaggingapi.get_resources(
>                         TagFilters=tag_filters, ResourceTypeFilters=["rds:cluster"]
>                     )["ResourceTagMappingList"]
>                 )
>                 # Put an empty list in db-cluster-id in filters to get InvalidParameterCombination. So, put the dummy value by default.
>                 clusters = ["DummyForAvoidInvalidParameterCombination"] + [
>                     i["ResourceARN"].split(":")[-1]
>                     for i in resource_tag_mapping_list_clusters
>                 ]
>                 cluster_filters = self._update_filters(
>                     cluster_filters, "db-cluster-id", clusters
286a347
>                 all_clusters += _describe_db_clusters(connection, cluster_filters, strict=strict)
298a360
>         resource_tag_filters = self.get_option("resource_tag_filters")
302a365,367
>         tag_filters = self._ansible_dict_to_boto3_resourcegroupstaggingapi_filter_list(
>             resource_tag_filters
>         )
305,307c370
<             cluster_filters = ansible_dict_to_boto3_filter_list(
<                 {"db-cluster-id": filters["db-cluster-id"]}
<             )
---
>             cluster_filters = ansible_dict_to_boto3_filter_list({"db-cluster-id": filters["db-cluster-id"]})
315a379
>             tag_filters,

実際の使用例

aws_rds_from_resource_tag.ymlを以下のように設定

plugin: aws_rds_from_resource_tag
regions:
  - ap-northeast-1
  - ap-northeast-3
include_clusters: yes
resource_tag_filters:
  EnvironmentName: hoge-fuga
statuses:
  - available
  - creating

groups:
  AuroraCluster: "'ap-northeast-1' in db_cluster_arn"
  AuroraBackupCluster: "'ap-northeast-3' in db_cluster_arn"
  AuroraInstance: "'ap-northeast-1' in db_instance_arn"

コマンドを実行

$ ansible-inventory -i inventory/aws_rds_from_resource_tag.yml --graph
@all:
  |--@ungrouped:
  |--@aws_rds:
  |  |--hoge-fuga-aurora-2-instance-az-a
  |  |--hoge-fuga-aurora-2-822366f0
  |--@AuroraInstance:
  |  |--hoge-fuga-aurora-2-instance-az-a
  |--@AuroraCluster:
  |  |--hoge-fuga-aurora-2-822366f0

開発時のテスト・デバッグ

通常のansibleと同様に、-v でデバッグログを表示できるので、 -vvvvvで最大のデバッグ出力量にして実行すると、Python側のスタックトレースまで見れるので原因調査がしやすい

$ ansible-inventory -i inventory/aws_rds_from_resource_tag.yml --graph -vvvvv
ansible-inventory [core 2.18.4]
~~~~
ubuntu@ip-10-0-13-174:~/$  ansible-inventory -i inventory/aws_rds_from_resource_tag.yml --graph -vvvvv
ansible-inventory [core 2.18.4]
  config file = /home/ubuntu//ansible.cfg
  configured module search path = ['/home/ubuntu//library']
  ansible python module location = /usr/local/lib/python3.12/dist-packages/ansible
  ansible collection location = /home/ubuntu/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/local/bin/ansible-inventory
  python version = 3.12.3 (main, Feb  4 2025, 14:48:35) [GCC 13.3.0] (/usr/bin/python3)
  jinja version = 3.1.6
  libyaml = True
Using /home/ubuntu//ansible.cfg as config file
setting up inventory plugins
Loading collection ansible.builtin from
host_list declined parsing /home/ubuntu/inventory/aws_rds_from_resource_tag.yml as it did not pass its verify_file() method
script declined parsing /home/ubuntu/inventory/aws_rds_from_resource_tag.yml as it did not pass its verify_file() method
Loading collection amazon.aws from /usr/local/lib/python3.12/dist-packages/ansible_collections/amazon/aws
Using inventory plugin 'aws_rds_from_resource_tag' to process inventory source '/home/ubuntu/inventory/aws_rds_from_resource_tag.yml'
toml declined parsing /home/ubuntu/inventory/aws_rds_from_resource_tag.yml as it did not pass its verify_file() method
[WARNING]:  * Failed to parse /home/ubuntu/inventory/aws_rds_from_resource_tag.yml with auto plugin:
Parameter validation failed: Unknown parameter in TagFilters[0]: "Name", must be one of:
Key, Values
  File "/usr/local/lib/python3.12/dist-packages/ansible/inventory/manager.py", line 292, in parse_source
    plugin.parse(self._inventory, self._loader, source, cache=cache)
  File "/usr/local/lib/python3.12/dist-packages/ansible/plugins/inventory/auto.py", line 58, in parse
    plugin.parse(inventory, loader, path, cache=cache)
  File "/home/ubuntu/inventory/aws_rds_from_resource_tag.py", line 376, in parse
    results = self._get_all_db_hosts(
              ^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ubuntu/inventory/aws_rds_from_resource_tag.py", line 320, in _get_all_db_hosts
    resourcegroupstaggingapi.get_resources(
  File "/usr/local/lib/python3.12/dist-packages/botocore/client.py", line 570, in _api_call
    return self._make_api_call(operation_name, kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/dist-packages/botocore/context.py", line 124, in wrapper
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/dist-packages/botocore/client.py", line 988, in _make_api_call
    request_dict = self._convert_to_request_dict(
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/dist-packages/botocore/client.py", line 1055, in _convert_to_request_dict
    request_dict = self._serializer.serialize_to_request(
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/dist-packages/botocore/validate.py", line 381, in serialize_to_request
    raise ParamValidationError(report=report.generate_report())
[WARNING]:  * Failed to parse /home/ubuntu/inventory/aws_rds_from_resource_tag.yml with yaml plugin:
Plugin configuration YAML file, not YAML inventory
  File "/usr/local/lib/python3.12/dist-packages/ansible/inventory/manager.py", line 292, in parse_source
    plugin.parse(self._inventory, self._loader, source, cache=cache)
  File "/usr/local/lib/python3.12/dist-packages/ansible/plugins/inventory/yaml.py", line 113, in parse
    raise AnsibleParserError('Plugin configuration YAML file, not YAML inventory')
[WARNING]:  * Failed to parse /home/ubuntu/inventory/aws_rds_from_resource_tag.yml with ini plugin:
Invalid host pattern 'plugin:' supplied, ending in ':' is not allowed, this character is
reserved to provide a port.
  File "/usr/local/lib/python3.12/dist-packages/ansible/inventory/manager.py", line 292, in parse_source
    plugin.parse(self._inventory, self._loader, source, cache=cache)
  File "/usr/local/lib/python3.12/dist-packages/ansible/plugins/inventory/ini.py", line 137, in parse
    raise AnsibleParserError(e)
[WARNING]: Unable to parse /home/ubuntu/inventory/aws_rds_from_resource_tag.yml as an inventory source
ERROR! No inventory was parsed, please check your configuration and options.

開発してみた感想

  • はまりポイントもいくつかあるが、そこを把握すれば割とすんなり実装できた
  • amazon.aws コレクション自体が結構作りこまれているので、その資産を利用していくことが大事
  • まだゴリ押し実装の部分があるので、より洗練された実装にして、ansible側にコントリビューションしたい
5
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?