显示主机的自定义名称

Displaying a custom name for a host

我有一本用于处理 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 获取特定实例的 "Name" 标签(我这样做并将其存储在一个变量中以供剧本的几个部分使用)。

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

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

ec2.py 库存脚本的输出看起来像这样(t运行cated;它很长)。

{
  "_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"
  ],
}

您需要做的是在 ec2.py 上创建您自己的包装器(比如 my_ec2.py),它将 post 处理输出。想法是使用 behavioral hostvar ansible_ssh_host. You can use any language not only python. As long as it prints valid json on stdout you're good to go. Reference if needed.

这只是一点点工作。但希望 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) In the groups, can I only refer to things by one name? 2) There's no notion of an alias? 3) I'm wondering if I could use the IP addr in the groups and just modify the _meta part or if I need to do it all?

是*,否和否。


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

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

原始 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 returns 这个:

[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 一起玩,ansible 将在 54.149.9.198.

上执行它

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

HTH

如果你把

vpc_destination_variable = Name

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

对于较新的版本,至少适用于 Ansible 的 2.9 和 2.10 版本,aws_ec2 插件现在允许将其作为一个简单的配置,而无需围绕 [=36 创建任何 warper =]ec2.py.

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

所以诀窍是通过 hostnames 参数更改 EC2 实例的名称,使其具有人类可读的内容——例如来自实例上的 AWS 标签——然后使用 compose 参数将 ansible_host 设置为 private_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