|
|
|
@ -85,6 +85,7 @@ from six import iteritems
|
|
|
|
|
|
|
|
|
|
|
|
from ansible.module_utils.urls import open_url
|
|
|
|
from ansible.module_utils.urls import open_url
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CollinsDefaults(object):
|
|
|
|
class CollinsDefaults(object):
|
|
|
|
ASSETS_API_ENDPOINT = '%s/api/assets'
|
|
|
|
ASSETS_API_ENDPOINT = '%s/api/assets'
|
|
|
|
SPECIAL_ATTRIBUTES = set([
|
|
|
|
SPECIAL_ATTRIBUTES = set([
|
|
|
|
@ -174,8 +175,7 @@ class CollinsInventory(object):
|
|
|
|
# Formats asset search query to locate assets matching attributes, using
|
|
|
|
# Formats asset search query to locate assets matching attributes, using
|
|
|
|
# the CQL search feature as described here:
|
|
|
|
# the CQL search feature as described here:
|
|
|
|
# http://tumblr.github.io/collins/recipes.html
|
|
|
|
# http://tumblr.github.io/collins/recipes.html
|
|
|
|
attributes_query = [ '='.join(attr_pair)
|
|
|
|
attributes_query = ['='.join(attr_pair) for attr_pair in iteritems(attributes)]
|
|
|
|
for attr_pair in iteritems(attributes) ]
|
|
|
|
|
|
|
|
query_parameters = {
|
|
|
|
query_parameters = {
|
|
|
|
'details': ['True'],
|
|
|
|
'details': ['True'],
|
|
|
|
'operation': [operation],
|
|
|
|
'operation': [operation],
|
|
|
|
@ -190,8 +190,7 @@ class CollinsInventory(object):
|
|
|
|
# Locates all assets matching the provided query, exhausting pagination.
|
|
|
|
# Locates all assets matching the provided query, exhausting pagination.
|
|
|
|
while True:
|
|
|
|
while True:
|
|
|
|
if num_retries == self.collins_max_retries:
|
|
|
|
if num_retries == self.collins_max_retries:
|
|
|
|
raise MaxRetriesError("Maximum of %s retries reached; giving up" % \
|
|
|
|
raise MaxRetriesError("Maximum of %s retries reached; giving up" % self.collins_max_retries)
|
|
|
|
self.collins_max_retries)
|
|
|
|
|
|
|
|
query_parameters['page'] = cur_page
|
|
|
|
query_parameters['page'] = cur_page
|
|
|
|
query_url = "%s?%s" % (
|
|
|
|
query_url = "%s?%s" % (
|
|
|
|
(CollinsDefaults.ASSETS_API_ENDPOINT % self.collins_host),
|
|
|
|
(CollinsDefaults.ASSETS_API_ENDPOINT % self.collins_host),
|
|
|
|
@ -212,8 +211,7 @@ class CollinsInventory(object):
|
|
|
|
cur_page += 1
|
|
|
|
cur_page += 1
|
|
|
|
num_retries = 0
|
|
|
|
num_retries = 0
|
|
|
|
except:
|
|
|
|
except:
|
|
|
|
self.log.error("Error while communicating with Collins, retrying:\n%s",
|
|
|
|
self.log.error("Error while communicating with Collins, retrying:\n%s" % traceback.format_exc())
|
|
|
|
traceback.format_exc())
|
|
|
|
|
|
|
|
num_retries += 1
|
|
|
|
num_retries += 1
|
|
|
|
return assets
|
|
|
|
return assets
|
|
|
|
|
|
|
|
|
|
|
|
@ -232,19 +230,15 @@ class CollinsInventory(object):
|
|
|
|
def read_settings(self):
|
|
|
|
def read_settings(self):
|
|
|
|
""" Reads the settings from the collins.ini file """
|
|
|
|
""" Reads the settings from the collins.ini file """
|
|
|
|
|
|
|
|
|
|
|
|
config_loc = os.getenv('COLLINS_CONFIG',
|
|
|
|
config_loc = os.getenv('COLLINS_CONFIG', os.path.dirname(os.path.realpath(__file__)) + '/collins.ini')
|
|
|
|
os.path.dirname(os.path.realpath(__file__)) + '/collins.ini')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
config = ConfigParser.SafeConfigParser()
|
|
|
|
config = ConfigParser.SafeConfigParser()
|
|
|
|
config.read(os.path.dirname(os.path.realpath(__file__)) + '/collins.ini')
|
|
|
|
config.read(os.path.dirname(os.path.realpath(__file__)) + '/collins.ini')
|
|
|
|
|
|
|
|
|
|
|
|
self.collins_host = config.get('collins', 'host')
|
|
|
|
self.collins_host = config.get('collins', 'host')
|
|
|
|
self.collins_username = os.getenv('COLLINS_USERNAME',
|
|
|
|
self.collins_username = os.getenv('COLLINS_USERNAME', config.get('collins', 'username'))
|
|
|
|
config.get('collins', 'username'))
|
|
|
|
self.collins_password = os.getenv('COLLINS_PASSWORD', config.get('collins', 'password'))
|
|
|
|
self.collins_password = os.getenv('COLLINS_PASSWORD',
|
|
|
|
self.collins_asset_type = os.getenv('COLLINS_ASSET_TYPE', config.get('collins', 'asset_type'))
|
|
|
|
config.get('collins', 'password'))
|
|
|
|
|
|
|
|
self.collins_asset_type = os.getenv('COLLINS_ASSET_TYPE',
|
|
|
|
|
|
|
|
config.get('collins', 'asset_type'))
|
|
|
|
|
|
|
|
self.collins_timeout_secs = config.getint('collins', 'timeout_secs')
|
|
|
|
self.collins_timeout_secs = config.getint('collins', 'timeout_secs')
|
|
|
|
self.collins_max_retries = config.getint('collins', 'max_retries')
|
|
|
|
self.collins_max_retries = config.getint('collins', 'max_retries')
|
|
|
|
|
|
|
|
|
|
|
|
@ -268,16 +262,12 @@ class CollinsInventory(object):
|
|
|
|
|
|
|
|
|
|
|
|
parser = argparse.ArgumentParser(
|
|
|
|
parser = argparse.ArgumentParser(
|
|
|
|
description='Produces an Ansible Inventory file based on Collins')
|
|
|
|
description='Produces an Ansible Inventory file based on Collins')
|
|
|
|
parser.add_argument('--list',
|
|
|
|
parser.add_argument('--list', action='store_true', default=True, help='List instances (default: True)')
|
|
|
|
action='store_true', default=True, help='List instances (default: True)')
|
|
|
|
parser.add_argument('--host', action='store', help='Get all the variables about a specific instance')
|
|
|
|
parser.add_argument('--host',
|
|
|
|
parser.add_argument('--refresh-cache', action='store_true', default=False,
|
|
|
|
action='store', help='Get all the variables about a specific instance')
|
|
|
|
help='Force refresh of cache by making API requests to Collins '
|
|
|
|
parser.add_argument('--refresh-cache',
|
|
|
|
|
|
|
|
action='store_true', default=False,
|
|
|
|
|
|
|
|
help='Force refresh of cache by making API requests to Collins ' \
|
|
|
|
|
|
|
|
'(default: False - use cache files)')
|
|
|
|
'(default: False - use cache files)')
|
|
|
|
parser.add_argument('--pretty',
|
|
|
|
parser.add_argument('--pretty', action='store_true', default=False, help='Pretty print all JSON output')
|
|
|
|
action='store_true', default=False, help='Pretty print all JSON output')
|
|
|
|
|
|
|
|
self.args = parser.parse_args()
|
|
|
|
self.args = parser.parse_args()
|
|
|
|
|
|
|
|
|
|
|
|
def update_cache(self):
|
|
|
|
def update_cache(self):
|
|
|
|
@ -290,8 +280,7 @@ class CollinsInventory(object):
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
server_assets = self.find_assets()
|
|
|
|
server_assets = self.find_assets()
|
|
|
|
except:
|
|
|
|
except:
|
|
|
|
self.log.error("Error while locating assets from Collins:\n%s",
|
|
|
|
self.log.error("Error while locating assets from Collins:\n%s" % traceback.format_exc())
|
|
|
|
traceback.format_exc())
|
|
|
|
|
|
|
|
return False
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
for asset in server_assets:
|
|
|
|
for asset in server_assets:
|
|
|
|
@ -315,8 +304,7 @@ class CollinsInventory(object):
|
|
|
|
if self.prefer_hostnames and self._asset_has_attribute(asset, 'HOSTNAME'):
|
|
|
|
if self.prefer_hostnames and self._asset_has_attribute(asset, 'HOSTNAME'):
|
|
|
|
asset_identifier = self._asset_get_attribute(asset, 'HOSTNAME')
|
|
|
|
asset_identifier = self._asset_get_attribute(asset, 'HOSTNAME')
|
|
|
|
elif 'ADDRESSES' not in asset:
|
|
|
|
elif 'ADDRESSES' not in asset:
|
|
|
|
self.log.warning("No IP addresses found for asset '%s', skipping",
|
|
|
|
self.log.warning("No IP addresses found for asset '%s', skipping" % asset)
|
|
|
|
asset)
|
|
|
|
|
|
|
|
continue
|
|
|
|
continue
|
|
|
|
elif len(asset['ADDRESSES']) < ip_index + 1:
|
|
|
|
elif len(asset['ADDRESSES']) < ip_index + 1:
|
|
|
|
self.log.warning(
|
|
|
|
self.log.warning(
|
|
|
|
@ -384,11 +372,11 @@ class CollinsInventory(object):
|
|
|
|
# Need to load index from cache
|
|
|
|
# Need to load index from cache
|
|
|
|
self.load_cache_from_cache()
|
|
|
|
self.load_cache_from_cache()
|
|
|
|
|
|
|
|
|
|
|
|
if not self.args.host in self.cache:
|
|
|
|
if self.args.host not in self.cache:
|
|
|
|
# try updating the cache
|
|
|
|
# try updating the cache
|
|
|
|
self.update_cache()
|
|
|
|
self.update_cache()
|
|
|
|
|
|
|
|
|
|
|
|
if not self.args.host in self.cache:
|
|
|
|
if self.args.host not in self.cache:
|
|
|
|
# host might not exist anymore
|
|
|
|
# host might not exist anymore
|
|
|
|
return self.json_format_dict({}, self.args.pretty)
|
|
|
|
return self.json_format_dict({}, self.args.pretty)
|
|
|
|
|
|
|
|
|
|
|
|
|