1

我有一本用于处理 EC2 实例的 Ansible 剧本。我正在使用动态清单 ( ec2.py ) 来获取我想要使用的实例组 ( hosts: tag_Service_Foo)。当我运行它时,它会产生如下输出:

GATHERING FACTS ***************************************************************
ok: [54.149.9.198]
ok: [52.11.22.29]
ok: [52.11.0.3]

但是,我可以从 Amazon 获取特定实例的“名称”标签(我这样做并将其存储在一个变量中,以便在剧本的几个部分中使用)。

有没有办法让 Ansible 在显示进度时将此字符串用作主机名?我希望看到更具描述性的内容(因为我没有记住 IP):

GATHERING FACTS ***************************************************************
ok: [main-server]
ok: [extra-server]
ok: [my-cool-server]

清单脚本的输出ec2.py如下所示(被截断;它很长)。

{
  "_meta": {
    "hostvars": {
      "54.149.9.198": {
        "ec2__in_monitoring_element": false,
        "ec2_ami_launch_index": "0",
        "ec2_architecture": "x86_64",
        "ec2_client_token": "xxx",
        "ec2_dns_name": "xxx",
        "ec2_ebs_optimized": false,
        "ec2_eventsSet": "",
        "ec2_group_name": "",
        "ec2_hypervisor": "xen",
        "ec2_id": "i-xxx",
        "ec2_image_id": "ami-xxx",
        "ec2_instance_type": "xxx",
        "ec2_ip_address": "xxx",
        "ec2_item": "",
        "ec2_kernel": "",
        "ec2_key_name": "xxx",
        "ec2_launch_time": "xxx",
        "ec2_monitored": xxx,
        "ec2_monitoring": "",
        "ec2_monitoring_state": "xxx",
        "ec2_persistent": false,
        "ec2_placement": "xxx",
        "ec2_platform": "",
        "ec2_previous_state": "",
        "ec2_previous_state_code": 0,
        "ec2_private_dns_name": "xxx",
        "ec2_private_ip_address": "xxx",
        "ec2_public_dns_name": "xxx",
        "ec2_ramdisk": "",
        "ec2_reason": "",
        "ec2_region": "xxx",
        "ec2_requester_id": "",
        "ec2_root_device_name": "/dev/xvda",
        "ec2_root_device_type": "ebs",
        "ec2_security_group_ids": "xxx",
        "ec2_security_group_names": "xxx",
        "ec2_sourceDestCheck": "true",
        "ec2_spot_instance_request_id": "",
        "ec2_state": "running",
        "ec2_state_code": 16,
        "ec2_state_reason": "",
        "ec2_subnet_id": "subnet-xxx",
        "ec2_tag_Name": "main-server",
        "ec2_tag_aws_autoscaling_groupName": "xxx",
        "ec2_virtualization_type": "hvm",
        "ec2_vpc_id": "vpc-xxx"
      }
    }
  }
  "tag_Service_Foo": [
    "54.149.9.198",
    "52.11.22.29",
    "52.11.0.3"
  ],
}
4

3 回答 3

2

您需要做的是创建自己的包装器(比如my_ec2.py),然后ec2.py处理输出。想法是使用行为 hostvaransible_ssh_host。您可以使用任何语言,不仅是 python。只要它在标准输出上打印有效的 json 就可以了。需要时参考

这将是一点点工作。但希望 sudo 代码会有所帮助:

output_json_map = new map
for each group in <ec2_output>: # e.g. tag_Service_Foo, I think there would be another 
                                # key in the output that contains list of group names.
  for each ip_address in group:
    hname = ec2_output._meta.hostvars.find(ip_address).find(ec2_tag_Name)

    # Add new host to the group member list
    output_json_map.add(key=group, value=hname)
    copy all vars from ec2_output._meta.hostvars.<ip_address>
                  to output_json_map._meta.hostvars.<hname>
    # Assign the IP address of this host to the ansible_ssh_host
    # in hostvars for this host
    output_json_map.add(key=_meta.hostvars.<hname>.ansible_ssh_host,
                        value=ip_address)
    output_json_map.add(key=_meta.hostvars.find(ip_address).ansible_ssh_host,
                        value=ip_address)

print output_json_map to stdout

例如,对于您的示例,输出my_ec2.py应该是:

{
  "_meta": {
    "hostvars": {
      "main-server": {
        "ansible_ssh_host": "54.149.9.198"
        --- snip ---
        "ec2_tag_Name": "main-server",
        --- snip ---
      },
      "extra-server": {
        "ansible_ssh_host": "52.11.22.29"
        --- snip ---
        "ec2_tag_Name": "extra-server",
        --- snip ---
      },
      <other hosts from all groups>
    }
  }
  "tag_Service_Foo": [
    "main-server",
    "extra-server",
    <other hosts in this group>
  ],
  "some other group": [
    <hosts in this group>,
    ...
  ],
}

显然,使用它my_ec2.py而不是ec2.py作为库存文件。:-)

- 编辑 -

1) 在群里,我可以只用一个名字来指代事物吗?2)没有别名的概念吗?3) 我想知道是否可以在组中使用 IP 地址并只修改 _meta 部分,或者我是否需要全部完成?

是*,没有和没有。


* 从技术上讲,首先是应该是否。让我解释。

我们在这里做的事情可以用这样的静态库存文件来完成:

原始ec2.py返回的 json 等效于以下库存文件:

[tag_Service_Foo]
54.149.9.198 ec2_tag_Name="main-server"  ec2_previous_state_code="0" ...
52.11.22.29  ec2_tag_Name="extra-server" ec2_previous_state_code="0" ...

我们的新my_ec2.py返回:

[tag_Service_Foo]
main-server  ansible_ssh_host="54.149.9.198" ec2_tag_Name="main-server"  ec2_previous_state_code="0" ...
extra-server ansible_ssh_host="52.11.22.29"  ec2_tag_Name="extra-server" ec2_previous_state_code="0" ...

# Technically it's possible to create "an alias" for main-server like this:
main-server-alias  ansible_ssh_host="54.149.9.198" ec2_tag_Name="main-server"  ec2_previous_state_code="0" ...

现在您可以main-server-alias在主机列表中运行 play with 并且 ansible 将在54.149.9.198.

但是,这是一个很大的问题,当您使用 'all' 作为主机模式运行游戏时,ansible 会main-server-aliasmain-server. 因此,您创建的是一个上下文中的别名和另一个上下文中的新主机。我没有测试过这个BUT 部分,所以如果你发现其他情况,请回来纠正我。

高温高压

于 2015-03-30T15:41:22.703 回答
1

如果你把

vpc_destination_variable = Name

在您的ec2.ini文件中,这也应该有效。

于 2015-12-23T20:53:04.137 回答
0

对于更新的版本,至少适用于 Ansible 的 2.9 和 2.10 版本,该aws_ec2插件现在允许将其作为简单的配置,而无需围绕ec2.py创建任何变形器。

这可以使用参数hostnames和的组合来完成compose

所以诀窍是通过hostnames参数更改 EC2 实例的名称,使其具有人类可读的内容——例如来自实例上的 AWS 标签——然后使用compose参数将 设置ansible_hostprivate_ip_addresspublic_ip_addressprivate_dns_namepublic_dns_name允许连接, 仍然。

这将是插件的最小配置,以允许这样做:

plugin: aws_ec2
hostnames:
  - tag:Name 
  # ^-- Given that you indeed have a tag named "Name" on your EC2 instances
compose:
  ansible_host: public_dns_address

请注意,在 AWS 中,标签不是唯一的,因此您可以将多个实例标记为相同的名称,但在 Ansible 中,主机名是唯一的。这意味着您可能会更好地将带有后缀的名称与tag:Name真正独特的东西(例如实例 ID)组合起来。

就像是:

plugin: aws_ec2
hostnames:
  - name: 'instance-id'
    separator: '_'
    prefix: 'tag:Name'
compose:
  ansible_host: public_dns_address
于 2021-10-21T19:26:41.237 回答