困ったこと
- pagenationがないので、100以上クラスターがあると取得できなくなる場合が生まれる
- describe_db_instance / describe_db_clusterのフィルターが完全一致しか対応していないので、部分一致の場合毎回全件取得しないといけない。そのためインベントリ取得のオーバヘッドが大きい
- タグでのフィルターもできない
これを参考に↓を使ってリソースを絞り込んでからdescribe_db_instance / describe_db_clusterを実行する
はまったところ
- 追加の引数を入れた場合にDOCUMENTATIONに書かないと読み込みできない
- 設定ファイル名をコード内で制御しているので変えないといけない
- https://github.com/ansible-collections/amazon.aws/blob/9.3.0/plugins/inventory/aws_rds.py#L167-L168 - ansible側から渡したタグフィルター情報をboto3側に渡す形式にするための変換ロジックの実装が必要
- もともと、そういった用途にansible_dict_to_boto3_filter_listのようなの関数が用意されているが、resourcegroupstraggingapiでのタグフィルターで渡すデータ形式が異なるため使用できない
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)
元のコードとの差分
- モジュールに引き渡す引数にタグフィルター用のresource_tag_filtersを追加
- ansible側から渡したタグフィルター情報をboto3側に渡す形式にするための変換ロジックである
_ansible_dict_to_boto3_resourcegroupstaggingapi_filter_list
の実装 - resourcegroupstaggingapiからリソースを検索し、結果をfilterに追加するロジックの実装
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側にコントリビューションしたい