blob: 56acd2df034fafc2fea83fe70491465e1d6f79b3 [file] [log] [blame]
#!/usr/bin/env python3
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
"""A python script that converts TrafficOps information into an Ansible Inventory"""
import json
import argparse
import os
import collections
from trafficops.tosession import TOSession
def empty_inventory():
"""Generate a valid empty inventory"""
return {'_meta': {'hostvars': {}}}
class AnsibleInventory():
"""Wrapper class for needed methods"""
def __init__(self, user, password, url, verify_cert):
"""Init base members"""
self.to_user = user
self.to_pass = password
self.to_url = url
self.verify_cert = verify_cert
@staticmethod
def populate_server_profile_vars(api, profile_id):
"""Generate the server profile variables once as we see it"""
server_vars = {}
server_vars['hosts'] = []
server_vars['vars'] = {}
profile = api.get_profiles(id=profile_id)[0]
server_vars['vars']['server_profile_description'] = profile[0]['description']
server_vars['vars']['server_profile_type'] = profile[0]['type']
server_vars['vars']['server_profile_routingDisabled'] = profile[0]['routingDisabled']
server_vars['vars']['server_profile_parameters'] = []
params = api.get_parameters_by_profile_id(id=profile_id)[0]
for param in params:
tmp_param = {
'name': param['name'],
'value': param['value'],
'configFile': param['configFile']}
server_vars['vars']['server_profile_parameters'].append(tmp_param)
return server_vars
@staticmethod
def populate_cachegroups(api, cachegroup_id):
"""Generate the values for cachegroups once on first sight"""
var_data = {}
cgdata = collections.namedtuple(
'Cgdata', [
'cgvars', 'primary_parent_group_name', 'secondary_parent_group_name'])
var_data['hosts'] = []
var_data['vars'] = {}
cachegroup = api.get_cachegroups(id=cachegroup_id)[0]
var_data['vars']['cachegroup_name'] = cachegroup[0]['name']
var_data['vars']['cachegroup_shortName'] = cachegroup[0]['shortName']
var_data['vars']['cachegroup_parentCachegroupName'] = \
cachegroup[0]['parentCachegroupName']
var_data['vars']['cachegroup_secondaryParentCachegroupName'] = \
cachegroup[0]['secondaryParentCachegroupName']
var_data['vars']['cachegroup_typeName'] = cachegroup[0]['typeName']
if cachegroup[0]['parentCachegroupName'] is None:
flat_parent_cg = "parentCachegroup|None"
else:
flat_parent_cg = "parentCachegroup|" + \
cachegroup[0]['parentCachegroupName']
if cachegroup[0]['secondaryParentCachegroupName'] is None:
flat_second_parent_cg = "secondaryParentCachegroup|None"
else:
flat_second_parent_cg = "secondaryParentCachegroup|" + \
cachegroup[0]['secondaryParentCachegroupName']
out = cgdata(cgvars=var_data,
primary_parent_group_name=flat_parent_cg,
secondary_parent_group_name=flat_second_parent_cg)
return out
def generate_inventory_list(self, target_to):
"""Generate the inventory list for the specified TrafficOps instance"""
with TOSession(self.to_url, verify_cert=self.verify_cert) as traffic_ops_api:
traffic_ops_api.login(self.to_user, self.to_pass)
servers = traffic_ops_api.get_servers()[0]
out = {}
out['_meta'] = {}
out['_meta']['hostvars'] = {}
out[target_to] = {}
out[target_to]['hosts'] = []
out["ungrouped"] = {}
out['ungrouped']['hosts'] = []
out['cachegroup'] = {}
out['cachegroup']['children'] = []
out['server_type'] = {}
out['server_type']['children'] = []
out['server_cdnName'] = {}
out['server_cdnName']['children'] = []
out['server_profile'] = {}
out['server_profile']['children'] = []
out['server_status'] = {}
out['server_status']['children'] = []
for server in servers:
fqdn = server['hostName'] + '.' + server['domainName']
out["ungrouped"]['hosts'].append(fqdn)
out[target_to]['hosts'].append(fqdn)
out['_meta']['hostvars'][fqdn] = {}
out['_meta']['hostvars'][fqdn]['server_toFQDN'] = target_to
out['_meta']['hostvars'][fqdn]['server_cachegroup'] = server['cachegroup']
out['_meta']['hostvars'][fqdn]['server_cdnName'] = server['cdnName']
out['_meta']['hostvars'][fqdn]['server_id'] = server['id']
out['_meta']['hostvars'][fqdn]['server_ipAddress'] = server['ipAddress']
out['_meta']['hostvars'][fqdn]['server_ip6Address'] = server['ip6Address']
out['_meta']['hostvars'][fqdn]['server_offlineReason'] = server['offlineReason']
out['_meta']['hostvars'][fqdn]['server_physLocation'] = server['physLocation']
out['_meta']['hostvars'][fqdn]['server_profile'] = server['profile']
out['_meta']['hostvars'][fqdn]['server_profileDesc'] = server['profileDesc']
out['_meta']['hostvars'][fqdn]['server_status'] = server['status']
out['_meta']['hostvars'][fqdn]['server_type'] = server['type']
flat_server_profile = "server_profile|" + server['profile']
flat_cachegroup = "cachegroup|" + server['cachegroup']
flat_server_type = "server_type|" + server['type']
flat_server_cdn_name = "server_cdnName|" + server['cdnName']
flat_server_status = "server_status|" + server['status']
if flat_server_profile not in out:
out['server_profile']['children'].append(
flat_server_profile)
out[flat_server_profile] = self.populate_server_profile_vars(
traffic_ops_api, server['profileId'])
out[flat_server_profile]['hosts'].append(fqdn)
if flat_cachegroup not in out:
out['cachegroup']['children'].append(flat_cachegroup)
cgdata = self.populate_cachegroups(
traffic_ops_api,
server['cachegroupId'])
out[flat_cachegroup] = cgdata.cgvars
flat_parent_cg = cgdata.primary_parent_group_name
flat_second_parent_cg = cgdata.secondary_parent_group_name
if flat_parent_cg not in out:
out[flat_parent_cg] = {}
out[flat_parent_cg]['children'] = []
if flat_second_parent_cg not in out:
out[flat_second_parent_cg] = {}
out[flat_second_parent_cg]['children'] = []
out[flat_parent_cg]['children'].append(flat_cachegroup)
out[flat_second_parent_cg]['children'].append(
flat_cachegroup)
out[flat_cachegroup]['hosts'].append(fqdn)
if flat_server_type not in out:
out['server_type']['children'].append(flat_server_type)
out[flat_server_type] = {}
out[flat_server_type]['hosts'] = []
out[flat_server_type]['hosts'].append(fqdn)
if flat_server_cdn_name not in out:
out['server_cdnName']['children'].append(
flat_server_cdn_name)
out[flat_server_cdn_name] = {}
out[flat_server_cdn_name]['hosts'] = []
out[flat_server_cdn_name]['hosts'].append(fqdn)
if flat_server_status not in out:
out['server_status']['children'].append(flat_server_status)
out[flat_server_status] = {}
out[flat_server_status]['hosts'] = []
out[flat_server_status]['hosts'].append(fqdn)
return out
def to_inventory(self):
"""A wrapper function blending the target url in"""
return self.generate_inventory_list(self.to_url)
#
# Thanks to Maxim for the snipit on handling bool parameters.
# https://stackoverflow.com/questions/15008758/parsing-boolean-values-with-argparse
#
def str2bool(x):
"""A helper function to help with truthiness"""
if isinstance(x, bool):
return x
if x.lower() in ('yes', 'true', 't', 'y', '1'):
return True
if x.lower() in ('no', 'false', 'f', 'n', '0'):
return False
raise argparse.ArgumentTypeError('Boolean value expected.')
if __name__ == "__main__":
PARSER = argparse.ArgumentParser(
description='Generate an Ansible inventory from TrafficOps')
PARSER.add_argument(
'--username',
type=str,
metavar='username',
default=os.environ.get('TO_USER', None),
help='TrafficOps Username. Environment Var: TO_USER Default: None')
PARSER.add_argument(
'--password',
type=str,
metavar='password',
default=os.environ.get('TO_PASSWORD', None),
help='TrafficOps Password. Environment Var: TO_PASSWORD Default: None')
PARSER.add_argument(
'--url',
type=str,
metavar='to.kabletown.invalid:8443',
default=os.environ.get('TO_URL', None),
help='TrafficOps FQDN and optional HTTPS Port. Environment Var: TO_URL Default: None')
PARSER.add_argument(
'--verify_cert',
type=str2bool,
default=os.environ.get('TO_VERIFY_CERT', "true"),
metavar="(true, false, yes, no, t, f, y, n, 0, or 1)",
help='Perform SSL Certificate Verification. Environment Var: TO_VERIFY_CERT Default: true')
PARSER.add_argument(
'--list',
action='store_true',
help='Primary argument to enable retrieval of TO data. Required per calling convention.')
PARSER.add_argument(
'--host',
type=str,
metavar='do_not_use',
default=None,
help='Ignored parameter that must be present due to calling convention.')
ARGS = PARSER.parse_args()
if ARGS.username and ARGS.password and ARGS.url:
if ARGS.list:
INVENTORY = AnsibleInventory(
ARGS.username,
ARGS.password,
ARGS.url,
ARGS.verify_cert).to_inventory()
# Since we're supplying hostvar metadata, --host support isn't required
else:
INVENTORY = empty_inventory()
else:
INVENTORY = empty_inventory()
print(json.dumps(INVENTORY))