1#!/usr/bin/env python
2
3# (c) 2015, Marc Abramowitz <marca@surveymonkey.com>
4#
5# This file is part of Ansible.
6#
7# Ansible is free software: you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation, either version 3 of the License, or
10# (at your option) any later version.
11#
12# Ansible is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
19
20# Dynamic inventory script which lets you use nodes discovered by Serf
21# (https://serfdom.io/).
22#
23# Requires the `serfclient` Python module from
24# https://pypi.org/project/serfclient/
25#
26# Environment variables
27# ---------------------
28#   - `SERF_RPC_ADDR`
29#   - `SERF_RPC_AUTH`
30#
31# These variables are described at https://www.serfdom.io/docs/commands/members.html#_rpc_addr
32
33import argparse
34import collections
35import os
36import sys
37
38# https://pypi.org/project/serfclient/
39from serfclient import SerfClient, EnvironmentConfig
40
41import json
42
43_key = 'serf'
44
45
46def _serf_client():
47    env = EnvironmentConfig()
48    return SerfClient(host=env.host, port=env.port, rpc_auth=env.auth_key)
49
50
51def get_serf_members_data():
52    return _serf_client().members().body['Members']
53
54
55def get_nodes(data):
56    return [node['Name'] for node in data]
57
58
59def get_groups(data):
60    groups = collections.defaultdict(list)
61
62    for node in data:
63        for key, value in node['Tags'].items():
64            groups[value].append(node['Name'])
65
66    return groups
67
68
69def get_meta(data):
70    meta = {'hostvars': {}}
71    for node in data:
72        meta['hostvars'][node['Name']] = node['Tags']
73    return meta
74
75
76def print_list():
77    data = get_serf_members_data()
78    nodes = get_nodes(data)
79    groups = get_groups(data)
80    meta = get_meta(data)
81    inventory_data = {_key: nodes, '_meta': meta}
82    inventory_data.update(groups)
83    print(json.dumps(inventory_data))
84
85
86def print_host(host):
87    data = get_serf_members_data()
88    meta = get_meta(data)
89    print(json.dumps(meta['hostvars'][host]))
90
91
92def get_args(args_list):
93    parser = argparse.ArgumentParser(
94        description='ansible inventory script reading from serf cluster')
95    mutex_group = parser.add_mutually_exclusive_group(required=True)
96    help_list = 'list all hosts from serf cluster'
97    mutex_group.add_argument('--list', action='store_true', help=help_list)
98    help_host = 'display variables for a host'
99    mutex_group.add_argument('--host', help=help_host)
100    return parser.parse_args(args_list)
101
102
103def main(args_list):
104    args = get_args(args_list)
105    if args.list:
106        print_list()
107    if args.host:
108        print_host(args.host)
109
110
111if __name__ == '__main__':
112    main(sys.argv[1:])
113