d2dce9c141
List a lot of useful info about a user: - all projects he's member of - for each project/region all servers, volumes, snapshots, routers, networks, floating ips, ... usage: user-info.py [-h] [-a] [-v] USERNAME Show information (servers, volumes, networks, ...) for a user. Search in all projects he's member of, and optionally in all regions (-a). positional arguments: USERNAME username to search optional arguments: -h, --help show this help message and exit -a, --all-regions query all regions -v, --verbose verbose Change-Id: I05694c016b16bc2fb0a43a1b30cbd3428ba6fe5b
281 lines
14 KiB
Python
Executable File
281 lines
14 KiB
Python
Executable File
#!/usr/bin/env python
|
|
#
|
|
# Copyright (c) 2015 SWITCH http://www.switch.ch
|
|
#
|
|
# 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.
|
|
|
|
# Author: Valery Tschopp <valery.tschopp@switch.ch>
|
|
# Date: 2015-08-27
|
|
# Update: 2016-04-04 - all regions from keystone v3 api
|
|
|
|
import sys
|
|
import os
|
|
import argparse
|
|
import keystoneclient
|
|
import novaclient
|
|
import cinderclient
|
|
from keystoneclient.v3 import client as keystone_v3
|
|
from novaclient import client as nova_client
|
|
from cinderclient.v2 import client as cinder_client
|
|
from neutronclient.v2_0 import client as neutron_client
|
|
|
|
def get_environ(key, verbose=False):
|
|
if key not in os.environ:
|
|
print "ERROR:", key, "not define in environment"
|
|
sys.exit(1)
|
|
if verbose:
|
|
if 'password' in key.lower():
|
|
key_value = '*' * len(os.environ[key])
|
|
else:
|
|
key_value = os.environ[key]
|
|
print "{}: {}".format(key, key_value)
|
|
return os.environ[key]
|
|
|
|
|
|
def main():
|
|
"""Shows user info (servers, volumes, snapshots, routers, networks, ...).
|
|
|
|
List a lot of useful info about a user:
|
|
- all projects he's member of
|
|
- for each project/region
|
|
all servers, volumes, snapshots, routers, networks, floating ips, ...
|
|
"""
|
|
parser = argparse.ArgumentParser(
|
|
description="Show information (servers, volumes, networks, ...) for a user. Search in all projects he's member of, and optionally in all regions (-a).")
|
|
parser.add_argument('-a', '--all-regions', help='query all regions', action='store_true')
|
|
parser.add_argument('USERNAME', help="username to search")
|
|
parser.add_argument('-v', '--verbose', help='verbose', action='store_true')
|
|
if len(sys.argv) < 2:
|
|
parser.print_help()
|
|
sys.exit(1)
|
|
args = parser.parse_args()
|
|
|
|
# get OS_* environment variables
|
|
os_auth_url = get_environ('OS_AUTH_URL', args.verbose)
|
|
os_username = get_environ('OS_USERNAME', args.verbose)
|
|
os_password = get_environ('OS_PASSWORD', args.verbose)
|
|
os_tenant_name = get_environ('OS_TENANT_NAME', args.verbose)
|
|
os_region_name = get_environ('OS_REGION_NAME', args.verbose)
|
|
|
|
# keystone_V3 client requires a /v3 auth url
|
|
if '/v2.0' in os_auth_url:
|
|
os_auth_url_v3 = os_auth_url.replace('/v2.0', '/v3')
|
|
if args.verbose:
|
|
print "os_auth_url_v3:", os_auth_url_v3
|
|
|
|
keystone = keystone_v3.Client(username=os_username,
|
|
password=os_password,
|
|
project_name=os_tenant_name,
|
|
auth_url=os_auth_url_v3)
|
|
|
|
# all regions available
|
|
all_regions = []
|
|
for region in keystone.regions.list():
|
|
all_regions.append(region.id)
|
|
|
|
# regions to use
|
|
region_names = [os_region_name]
|
|
if args.all_regions:
|
|
if os_region_name in all_regions:
|
|
region_names = all_regions
|
|
|
|
# Openstack clients per region
|
|
nova_regions = {}
|
|
cinder_regions = {}
|
|
neutron_regions = {}
|
|
for region_name in region_names:
|
|
_nova = nova_client.Client(2,
|
|
os_username,
|
|
os_password,
|
|
os_tenant_name,
|
|
auth_url=os_auth_url,
|
|
region_name=region_name)
|
|
nova_regions[region_name] = _nova
|
|
_cinder = cinder_client.Client(os_username,
|
|
os_password,
|
|
os_tenant_name,
|
|
auth_url=os_auth_url,
|
|
region_name=region_name)
|
|
cinder_regions[region_name] = _cinder
|
|
_neutron = neutron_client.Client(username=os_username,
|
|
password=os_password,
|
|
tenant_name=os_tenant_name,
|
|
auth_url=os_auth_url,
|
|
region_name=region_name)
|
|
neutron_regions[region_name] = _neutron
|
|
|
|
try:
|
|
username = args.USERNAME
|
|
user = keystone.users.find(name=username)
|
|
user_projects = keystone.projects.list(user=user)
|
|
|
|
print "User: {} [{}]: {} projects".format(user.name,
|
|
user.id,
|
|
len(user_projects))
|
|
for project in user_projects:
|
|
print " Project: {} [{}] - {}".format(project.name,
|
|
project.id,
|
|
project.description)
|
|
|
|
servers_search_opts = {'all_tenants': True, 'tenant_id': project.id}
|
|
volumes_search_opts = {'all_tenants': True, 'project_id': project.id}
|
|
neutron_search_opts = {'all_tenants': True, 'tenant_id': project.id}
|
|
for region in region_names:
|
|
|
|
# get clients for region
|
|
nova = nova_regions[region]
|
|
cinder = cinder_regions[region]
|
|
neutron = neutron_regions[region]
|
|
|
|
# servers
|
|
project_servers = nova.servers.list(search_opts=servers_search_opts)
|
|
servers = {}
|
|
for server in project_servers:
|
|
servers[server.id] = server
|
|
|
|
# volumes
|
|
project_volumes = cinder.volumes.list(search_opts=volumes_search_opts)
|
|
volumes = {}
|
|
for volume in project_volumes:
|
|
volumes[volume.id] = volume
|
|
|
|
# volume snapshots
|
|
project_volume_snapshots = cinder.volume_snapshots.list(search_opts=volumes_search_opts)
|
|
volume_snapshots = {}
|
|
for volume_snapshot in project_volume_snapshots:
|
|
volume_snapshots[volume_snapshot.id] = volume_snapshot
|
|
|
|
# floating IPs
|
|
resp = neutron.list_floatingips(**neutron_search_opts)
|
|
floatingips = {}
|
|
for floatingip in resp['floatingips']:
|
|
floatingips[floatingip['id']] = floatingip
|
|
|
|
resp = neutron.list_networks(**neutron_search_opts)
|
|
networks = {}
|
|
for network in resp['networks']:
|
|
networks[network['id']] = network
|
|
|
|
resp = neutron.list_routers(**neutron_search_opts)
|
|
routers = {}
|
|
for router in resp['routers']:
|
|
routers[router['id']] = router
|
|
|
|
#
|
|
# show info
|
|
#
|
|
if servers or volumes or volume_snapshots or floatingips or networks or routers:
|
|
print " Region:", region
|
|
if servers:
|
|
print " Servers:"
|
|
for id, server in servers.items():
|
|
print " Server: {} [{}] - {}".format(server.name, server.id, server.status)
|
|
volumes_attached = getattr(server,'os-extended-volumes:volumes_attached')
|
|
for volume_attached in volumes_attached:
|
|
volume_id = volume_attached['id']
|
|
if volume_id in volumes:
|
|
volume = volumes[volume_id]
|
|
volume_name = volume.name.rstrip() if volume.name else 'None'
|
|
for attachment in volume.attachments:
|
|
attached_server_id = attachment['server_id']
|
|
attached_device = attachment['device']
|
|
if attached_server_id == server.id:
|
|
print " Volume: {}: {} [{}] {}GB - {}".format(attached_device, volume_name, volume.id, volume.size, volume.status.upper())
|
|
# remove volume from list
|
|
volumes.pop(volume_id)
|
|
else:
|
|
print " ERROR: Volume {} [{}] not attached to Server {} [{}]".format(volume_name, volume.id, server.name, server.id)
|
|
|
|
if volumes:
|
|
print " Other Volumes:"
|
|
for id, volume in volumes.items():
|
|
volume_name = volume.name.rstrip() if volume.name else 'None'
|
|
print " Volume: {} [{}] {}GB - {}".format(volume_name, volume.id, volume.size, volume.status.upper())
|
|
for attachment in volume.attachments:
|
|
attached_server_id = attachment['server_id']
|
|
if attached_server_id in servers:
|
|
server_attached = servers[attached_server_id]
|
|
print " Attached to: {} [{}]:{}".format(server_attached.name, server_attached.id, attachment['device'])
|
|
else:
|
|
print " ERROR: attached to unknown Server [{}]:{}".format(attached_server_id, attachment['device'])
|
|
|
|
if volume_snapshots:
|
|
print " Volume Snapshots:"
|
|
for id, v_snapshot in volume_snapshots.items():
|
|
v_snapshot_name = v_snapshot.name.rstrip() if v_snapshot.name else 'None'
|
|
print " Snapshot: {} [{}] (Volume: [{}]) {}GB - {}".format(v_snapshot_name, v_snapshot.id, v_snapshot.volume_id, v_snapshot.size, v_snapshot.status.upper())
|
|
|
|
if floatingips:
|
|
print " Floating IPs:"
|
|
for id, floatingip in floatingips.items():
|
|
print " IP: {} [{}] - {}".format(floatingip['floating_ip_address'], floatingip['id'], floatingip['status'])
|
|
|
|
if routers:
|
|
print " Routers:"
|
|
for id, router in routers.items():
|
|
print " Router: {} [{}] - {}".format(router['name'], router['id'], router['status'])
|
|
resp = neutron.list_ports(device_id=id)
|
|
ifaces = resp['ports']
|
|
for iface in ifaces:
|
|
device_owner = iface['device_owner']
|
|
iface_info = ["Subnet: %s IP: %s" % (i['subnet_id'],i['ip_address']) for i in iface['fixed_ips']]
|
|
if device_owner == 'network:router_gateway':
|
|
resp = neutron.show_network(iface['network_id'])
|
|
iface_net = resp['network']
|
|
print " Interface: {} (Gateway External Network: {} [{}])".format(iface['id'], iface_net['name'], iface_net['id'])
|
|
elif device_owner == 'network:router_interface':
|
|
print " Interface: {} ({})".format(iface['id'], ",".join(iface_info))
|
|
else:
|
|
print " Interface: {} ({}) ({})".format(iface['id'], device_owner, ",".join(iface_info))
|
|
|
|
if networks:
|
|
print " Networks:"
|
|
for id, network in networks.items():
|
|
print " Network: {} [{}] - {}".format(network['name'], network['id'], network['status'])
|
|
for subnet_id in network['subnets']:
|
|
resp = neutron.show_subnet(subnet_id)
|
|
subnet = resp['subnet']
|
|
subnet_ipranges = ["IPRange: %s-%s" % (i['start'],i['end']) for i in subnet['allocation_pools']]
|
|
print " Subnet: {} [{}] (CIDR: {})".format(subnet['name'], subnet['id'], subnet['cidr'])
|
|
resp = neutron.list_ports(network_id=id)
|
|
ports = resp['ports']
|
|
for port in ports:
|
|
device_id = port['device_id']
|
|
device_owner = port['device_owner']
|
|
if device_id in servers:
|
|
server = servers[device_id]
|
|
print " Port: {} (Server: {} [{}])".format(port['id'], server.name, server.id, port['status'])
|
|
elif device_id in routers:
|
|
router = routers[device_id]
|
|
print " Port: {} (Router: {} [{}])".format(port['id'], router['name'], router['id'], port['status'])
|
|
elif device_owner == 'network:dhcp':
|
|
print " Port: {} (DHCP)".format(port['id'])
|
|
else:
|
|
print " Port: {} ({} [])".format(port['id'], device_owner, device_id, port['status'])
|
|
|
|
except keystoneclient.exceptions.NotFound as e:
|
|
print "ERROR: Username", username, "not found:", e.message
|
|
sys.exit(1)
|
|
|
|
except novaclient.exceptions.NotFound as e:
|
|
print "ERROR: not found:", e.message
|
|
sys.exit(1)
|
|
|
|
except Exception as e:
|
|
print "ERROR:", e.message
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|