Skip to content

Instantly share code, notes, and snippets.

@dstanek
Created October 18, 2016 15:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dstanek/0bb8e2cbd8395b49567cfa142d054382 to your computer and use it in GitHub Desktop.
Save dstanek/0bb8e2cbd8395b49567cfa142d054382 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
import json
import os
import subprocess
import sys
PYTHON = '/home/dstanek/.py-venvs/simple2/bin/python'
INVENTORY = '/home/dstanek/bin/openstack_inventory.py'
PERSONAL_CLOUD = 'personal_inventory.ini'
RAX_CLOUD = 'rax_inventory.ini'
def ssh(ip):
cmd = ['ssh'] + sys.argv[2:] + [ip]
os.execlp('ssh', *cmd)
def inventory_for(cloud_name):
p = subprocess.Popen([PYTHON, INVENTORY],
env={'INVENTORY_CONFIG': cloud_name})
stdout, stderr = p.communicate()
return json.loads(stdout)
inventory = json.loads(subprocess.check_output([PYTHON, INVENTORY]))
hostvars = inventory['_meta']['hostvars']
if len(sys.argv) < 2:
print('what host do you want to connect to?')
sys.exit(1)
hostname = sys.argv[1]
inventory = inventory_for(PERSONAL_CLOUD)
#inventory = json.loads(subprocess.check_output([PYTHON, INVENTORY]))
hostvars = inventory['_meta']['hostvars']
if hostname in hostvars:
ssh(hostvars[hostname]['ansible_host'])
user_hostname = 'dstanek-' + sys.argv[1]
inventory = inventory_for(RAX_CLOUD)
#inventory = json.loads(subprocess.check_output([PYTHON, INVENTORY]))
hostvars = inventory['_meta']['hostvars']
if user_hostname in hostvars:
ssh(hostvars[user_hostname]['ansible_host'])
print("neither host (%r or %r) was found" % (hostname, user_hostname))
sys.exit(2)
#!/usr/bin/env python
from __future__ import print_function
import json
import os
import time
import sys
import warnings
from ansible.module_utils import openstack as openstack_utils
from keystoneauth1 import loading
from keystoneauth1 import session
from novaclient import client
from os_client_config import config as cloud_config
from six.moves import configparser
warnings.filterwarnings('ignore')
NOVA_API_VERSION = '2'
CACHE_FILE_PREFIX = os.path.expanduser('~/.cache/openstack_inventory-')
class Server(object):
def __init__(self, nova_server, inv_config, region_name):
self._server = nova_server
self._host_group_key = inv_config.host_group_key
self._host_vars_key = inv_config.host_vars_key
self.region_name = region_name
@property
def name(self):
return self._server.name
@property
def preferred_ip(self):
if self._server.accessIPv4:
return self._server.accessIPv4
public_ips = openstack_utils.openstack_find_nova_addresses(
self._server.addresses, 'floating', 'public')
if public_ips:
return public_ips[0]
private_ips = openstack_utils.openstack_find_nova_addresses(
self._server.addresses, 'fixed', 'private')
if private_ips:
return private_ips[0]
raise Exception('TODO: better error message here')
@property
def host_groups(self):
data = self._server.metadata.get(self._host_group_key)
return data.split(',') if data else []
@property
def host_vars(self):
data = self._server.metadata.get(self._host_vars_key, '{}')
data = json.loads(data)
data['ansible_host'] = self.preferred_ip
return data
def __getattr__(self, name):
return getattr(self._server, name)
def get_servers(cloud, inv_config, region_name=None):
loader = loading.get_plugin_loader('password')
auth = loader.load_from_options(
auth_url=cloud.config['auth']['auth_url'],
username=cloud.config['auth']['username'],
password=cloud.config['auth']['password'],
project_id=cloud.config['auth']['project_id'])
region_name = region_name or cloud.config['region_name']
sess = session.Session(auth=auth)
nova = client.Client(NOVA_API_VERSION,
session=sess,
region_name=region_name)
for server in nova.servers.list():
server = Server(server, inv_config, region_name)
if inv_config.filter_user_id:
if server.user_id != inv_config.filter_user_id:
continue
yield server
class Inventory(object):
def __init__(self):
self._host_groups = {}
self._host_vars = {}
def add_server(self, server):
for host_group in server.host_groups:
group = self._host_groups.setdefault(host_group, [])
group.append(server.name)
# catch all group
self._host_groups.setdefault('all', []).append(server.name)
# region group
group_name = 'region-' + server.region_name
self._host_groups.setdefault(group_name, []).append(server.name)
self._host_vars[server.name] = server.host_vars
def as_json(self):
data = self._host_groups.copy()
data['_meta'] = {}
data['_meta']['hostvars'] = self._host_vars.copy()
return json.dumps(data, indent=4)
class InventoryConfig(object):
FILENAME = os.environ.get('INVENTORY_CONFIG', 'openstack_inventory.ini')
CONFIG_FILES = [
FILENAME,
os.path.join(os.getcwd(), FILENAME),
os.path.join(os.path.expanduser('~/.config/openstack'), FILENAME),
os.path.join('/etc/ansible/', FILENAME),
]
def __init__(self, cloud_config):
defaults = {
'host_group_key': None,
'host_vars_key': None,
'filter_user_id': None,
}
self._cfg = configparser.ConfigParser(defaults)
for filename in self.CONFIG_FILES:
if os.path.exists(filename):
self._cfg.read(filename)
break
self._validate(cloud_config)
def _validate(self, cloud_config):
self.cloud_name = self._cfg.get('openstack', 'cloud')
if not self.cloud_name:
clouds = ', '.join(cloud_config.get_cloud_names())
msg = 'Please set a valid cloud. Choices: %r' % clouds
raise ValueError(msg)
self.host_group_key = self._cfg.get('openstack', 'host_group_key')
self.host_vars_key = self._cfg.get('openstack', 'host_vars_key')
self.filter_user_id = self._cfg.get('openstack', 'filter_user_id')
self.region_names = self._cfg.get('openstack', 'regions', '').split(',')
def main():
cloud_cfg = cloud_config.OpenStackConfig()
inv_cfg = InventoryConfig(cloud_cfg)
cache_file = CACHE_FILE_PREFIX + inv_cfg.cloud_name
fresh = time.time() - (60 * 60 * 24)
if os.path.exists(cache_file) and os.stat(cache_file).st_mtime > fresh:
print(json.load(open(cache_file)))
return 0
inventory = Inventory()
cloud = cloud_cfg.get_one_cloud(inv_cfg.cloud_name)
for region_name in inv_cfg.region_names or [None]:
for server in get_servers(cloud, inv_cfg, region_name=region_name):
inventory.add_server(server)
inventory_json = inventory.as_json()
print(inventory_json)
json.dump(inventory_json, open(cache_file, 'w'))
return 0
if __name__ == "__main__":
try:
sys.exit(main())
except Exception as e:
print('ERROR: {}: {}'.format(e.__class__.__name__, e), file=sys.stderr)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment