Created
October 18, 2016 15:13
-
-
Save dstanek/0bb8e2cbd8395b49567cfa142d054382 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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