mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
Stacki inventory (#19608)
* adding inventory script for stacki * clean-up for consistency and error check * clean up imports and implement StrictVersion for requests
This commit is contained in:
parent
abe46dd75f
commit
541d2e8820
2 changed files with 198 additions and 0 deletions
191
contrib/inventory/stacki.py
Normal file
191
contrib/inventory/stacki.py
Normal file
|
@ -0,0 +1,191 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (c) 2016, Hugh Ma <hugh.ma@flextronics.com>
|
||||
#
|
||||
# This module is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This software is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Stacki inventory script
|
||||
# Configure stacki.yml with proper auth information and place in the following:
|
||||
# - ../inventory/stacki.yml
|
||||
# - /etc/stacki/stacki.yml
|
||||
# - /etc/ansible/stacki.yml
|
||||
# The stacki.yml file can contain entries for authentication information
|
||||
# regarding the Stacki front-end node.
|
||||
#
|
||||
# use_hostnames uses hostname rather than interface ip as connection
|
||||
#
|
||||
#
|
||||
|
||||
"""
|
||||
Example Usage:
|
||||
List Stacki Nodes
|
||||
$ ./stack.py --list
|
||||
|
||||
|
||||
Example Configuration:
|
||||
---
|
||||
stacki:
|
||||
auth:
|
||||
stacki_user: admin
|
||||
stacki_password: abc12345678910
|
||||
stacki_endpoint: http://192.168.200.50/stack
|
||||
use_hostnames: false
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
import yaml
|
||||
from distutils.version import StrictVersion
|
||||
|
||||
try:
|
||||
import json
|
||||
except:
|
||||
import simplejson as json
|
||||
|
||||
try:
|
||||
import requests
|
||||
except:
|
||||
sys.exit('requests package is required for this inventory script')
|
||||
|
||||
|
||||
CONFIG_FILES = ['/etc/stacki/stacki.yml', '/etc/ansible/stacki.yml']
|
||||
|
||||
|
||||
def stack_auth(params):
|
||||
endpoint = params['stacki_endpoint']
|
||||
auth_creds = {'USERNAME': params['stacki_user'],
|
||||
'PASSWORD': params['stacki_password']}
|
||||
|
||||
client = requests.session()
|
||||
client.get(endpoint)
|
||||
|
||||
init_csrf = client.cookies['csrftoken']
|
||||
|
||||
header = {'csrftoken': init_csrf, 'X-CSRFToken': init_csrf,
|
||||
'Content-type': 'application/x-www-form-urlencoded'}
|
||||
|
||||
login_endpoint = endpoint + "/login"
|
||||
|
||||
login_req = client.post(login_endpoint, data=auth_creds, headers=header)
|
||||
|
||||
csrftoken = login_req.cookies['csrftoken']
|
||||
sessionid = login_req.cookies['sessionid']
|
||||
|
||||
auth_creds.update(CSRFTOKEN=csrftoken, SESSIONID=sessionid)
|
||||
|
||||
return client, auth_creds
|
||||
|
||||
|
||||
def stack_build_header(auth_creds):
|
||||
header = {'csrftoken': auth_creds['CSRFTOKEN'],
|
||||
'X-CSRFToken': auth_creds['CSRFTOKEN'],
|
||||
'sessionid': auth_creds['SESSIONID'],
|
||||
'Content-type': 'application/json'}
|
||||
|
||||
return header
|
||||
|
||||
|
||||
def stack_host_list(endpoint, header, client):
|
||||
|
||||
stack_r = client.post(endpoint, data=json.dumps({ "cmd": "list host"}),
|
||||
headers=header)
|
||||
return json.loads(stack_r.json())
|
||||
|
||||
|
||||
def stack_net_list(endpoint, header, client):
|
||||
|
||||
stack_r = client.post(endpoint, data=json.dumps({ "cmd": "list host interface"}),
|
||||
headers=header)
|
||||
return json.loads(stack_r.json())
|
||||
|
||||
def format_meta(hostdata, intfdata, config):
|
||||
use_hostnames = config['use_hostnames']
|
||||
meta = dict(all=dict(hosts=list()),
|
||||
frontends=dict(hosts=list()),
|
||||
backends=dict(hosts=list()),
|
||||
_meta=dict(hostvars=dict()))
|
||||
|
||||
# Iterate through list of dicts of hosts and remove
|
||||
# environment key as it causes conflicts
|
||||
for host in hostdata:
|
||||
del host['environment']
|
||||
meta['_meta']['hostvars'][host['host']] = host
|
||||
meta['_meta']['hostvars'][host['host']]['interfaces'] = list()
|
||||
|
||||
# @bbyhuy to improve readability in next iteration
|
||||
|
||||
for intf in intfdata:
|
||||
if intf['host'] in meta['_meta']['hostvars']:
|
||||
meta['_meta']['hostvars'][intf['host']]['interfaces'].append(intf)
|
||||
if intf['default'] is True:
|
||||
meta['_meta']['hostvars'][intf['host']]['ansible_host'] = intf['ip']
|
||||
if not use_hostnames:
|
||||
meta['all']['hosts'].append(intf['ip'])
|
||||
if meta['_meta']['hostvars'][intf['host']]['appliance'] != 'frontend':
|
||||
meta['backends']['hosts'].append(intf['ip'])
|
||||
else:
|
||||
meta['frontends']['hosts'].append(intf['ip'])
|
||||
else:
|
||||
meta['all']['hosts'].append(intf['host'])
|
||||
if meta['_meta']['hostvars'][intf['host']]['appliance'] != 'frontend':
|
||||
meta['backends']['hosts'].append(intf['host'])
|
||||
else:
|
||||
meta['frontends']['hosts'].append(intf['host'])
|
||||
return meta
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(description='Stacki Inventory Module')
|
||||
group = parser.add_mutually_exclusive_group(required=True)
|
||||
group.add_argument('--list', action='store_true',
|
||||
help='List active hosts')
|
||||
group.add_argument('--host', help='List details about the specific host')
|
||||
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main():
|
||||
args = parse_args()
|
||||
|
||||
|
||||
if StrictVersion(requests.__version__) < StrictVersion("2.4.3"):
|
||||
sys.exit('requests>=2.4.3 is required for this inventory script')
|
||||
|
||||
try:
|
||||
config_files = CONFIG_FILES
|
||||
config_files.append(os.path.dirname(os.path.realpath(__file__)) + '/stacki.yml')
|
||||
config = None
|
||||
for cfg_file in config_files:
|
||||
if os.path.isfile(cfg_file):
|
||||
stream = open(cfg_file, 'r')
|
||||
config = yaml.load(stream)
|
||||
break
|
||||
if not config:
|
||||
sys.stderr.write("No config file found at {}\n".format(config_files))
|
||||
sys.exit(1)
|
||||
client, auth_creds = stack_auth(config['stacki']['auth'])
|
||||
header = stack_build_header(auth_creds)
|
||||
host_list = stack_host_list(config['stacki']['auth']['stacki_endpoint'], header, client)
|
||||
intf_list = stack_net_list(config['stacki']['auth']['stacki_endpoint'], header, client)
|
||||
final_meta = format_meta(host_list, intf_list, config)
|
||||
print(json.dumps(final_meta, indent=4))
|
||||
except Exception as e:
|
||||
sys.stderr.write('%s\n' % e.message)
|
||||
sys.exit(1)
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
7
contrib/inventory/stacki.yml
Normal file
7
contrib/inventory/stacki.yml
Normal file
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
stacki:
|
||||
auth:
|
||||
stacki_user: admin
|
||||
stacki_password: GhYgWut1hfGbbnstmbW3m-bJbeME-3EvC20rF1LHrDM
|
||||
stacki_endpoint: http://192.168.200.50/stack
|
||||
use_hostnames: false
|
Loading…
Reference in a new issue