Add JSON output and re-factor
Add a JSON output flag to enable this tool to more easily be called by other scripts and used in pipelines. Re-factor a bit, add a class and remove some code duplication Change-Id: If4586cf18a7e30580a00e6d9d1d7e166d4001aea
This commit is contained in:
parent
e3b5bc9634
commit
651cd91f8e
|
@ -1,10 +1,11 @@
|
|||
#!/usr/bin/env python
|
||||
# pylint: disable=import-error
|
||||
""" Utility to check validity of anti-affinity rules """
|
||||
|
||||
import os
|
||||
import sys
|
||||
import argparse
|
||||
from collections import defaultdict, Counter
|
||||
import json
|
||||
from collections import Counter
|
||||
from keystoneclient import session
|
||||
from keystoneclient.auth.identity import v2
|
||||
from keystoneclient.v2_0 import client as ksclient
|
||||
|
@ -20,78 +21,125 @@ def get_credentials():
|
|||
keystone_credentials['tenant_name'] = os.environ['OS_TENANT_NAME']
|
||||
return keystone_credentials
|
||||
|
||||
def get_args():
|
||||
""" Get commandline arguments """
|
||||
parser = argparse.ArgumentParser(description='Nova Server Group anti-affinity rule checker')
|
||||
parser.add_argument('--check', type=str, help='Validate the specified Server Group')
|
||||
parser.add_argument('--list', type=str, help='List instances and their hypervisors for a given Server Group')
|
||||
return parser.parse_args()
|
||||
class NovaConnect(object):
|
||||
"""
|
||||
Base Nova connection class
|
||||
"""
|
||||
def __init__(self, args):
|
||||
|
||||
def get_server(serverid):
|
||||
""" Return Server object """
|
||||
return nova.servers.get(serverid)
|
||||
credentials = get_credentials()
|
||||
ksclient.Client(**credentials)
|
||||
auth = v2.Password(**credentials)
|
||||
sess = session.Session(auth=auth)
|
||||
self.nova = nclient.Client(2, session=sess)
|
||||
self.json = args.json
|
||||
|
||||
def get_group_members(server_group_id):
|
||||
""" Return list of instance UUIDs present in a Server Group """
|
||||
server_group = nova.server_groups.get(server_group_id)
|
||||
if 'anti-affinity' in server_group.policies:
|
||||
return server_group.members
|
||||
else:
|
||||
return False
|
||||
def get_server(self, serverid):
|
||||
"""
|
||||
Return Server object
|
||||
"""
|
||||
return self.nova.servers.get(serverid)
|
||||
|
||||
def get_group_members(self, server_group_id):
|
||||
"""
|
||||
Return list of instance UUIDs present in a Server Group
|
||||
"""
|
||||
server_group = self.nova.server_groups.get(server_group_id)
|
||||
if 'anti-affinity' in server_group.policies:
|
||||
return server_group.members
|
||||
else:
|
||||
return False
|
||||
|
||||
def get_hypervisors(self, uid_list):
|
||||
"""
|
||||
Return a dict with hypervisors and names given a list of server uids
|
||||
"""
|
||||
ret = []
|
||||
for uid in uid_list:
|
||||
instance = self.get_server(uid)
|
||||
hypervisor = getattr(instance, 'OS-EXT-SRV-ATTR:hypervisor_hostname'.split('.')[0])
|
||||
ret.append({'id':uid, 'name':instance.name, 'hypervisor':hypervisor})
|
||||
return ret
|
||||
|
||||
def print_group_members(self, server_group_id):
|
||||
"""
|
||||
Output detail on Server Group instances and their hypervisors
|
||||
"""
|
||||
group_members = self.get_group_members(server_group_id)
|
||||
if group_members:
|
||||
output = self.get_hypervisors(group_members)
|
||||
if self.json:
|
||||
print json.dumps(output)
|
||||
else:
|
||||
table = create_table(['Instance ID', 'Instance Name', 'Hypervisor'])
|
||||
for instance in output:
|
||||
table.add_row([instance['id'], instance['name'], instance['hypervisor']])
|
||||
print table
|
||||
else:
|
||||
print "Server Group", server_group_id,\
|
||||
"empty or does not have an anti-affinity policy set."
|
||||
|
||||
def print_group_duplicates(self, server_group_id):
|
||||
"""
|
||||
Evaluate whether any instances in a SG
|
||||
have been scheduled to the same hypervisor
|
||||
"""
|
||||
group_members = self.get_group_members(server_group_id)
|
||||
if group_members:
|
||||
hypervisors = []
|
||||
instances = self.get_hypervisors(group_members)
|
||||
for instance in instances:
|
||||
hypervisors.append(instance['hypervisor'])
|
||||
dupes = [k for k, v in Counter(hypervisors).items() if v > 1]
|
||||
if dupes:
|
||||
instance_dupes = [instance for instance in instances
|
||||
if instance['hypervisor'] in dupes]
|
||||
if self.json:
|
||||
print json.dumps(instance_dupes)
|
||||
else:
|
||||
print "Anti-affinity rules violated in Server Group:",\
|
||||
server_group_id
|
||||
table = create_table(['Instance ID', 'Instance Name', 'Hypervisor'])
|
||||
for instance in instance_dupes:
|
||||
table.add_row([instance['id'], instance['name'], instance['hypervisor']])
|
||||
print table
|
||||
else:
|
||||
if not self.json:
|
||||
print "No anti-affinity rules violated for Server Group:", server_group_id
|
||||
else:
|
||||
if not self.json:
|
||||
print "Server Group", server_group_id,\
|
||||
"empty or does not have an anti-affinity policy set."
|
||||
|
||||
def create_table(fields):
|
||||
""" Boilerplate for PrettyTable """
|
||||
"""
|
||||
Boilerplate for PrettyTable
|
||||
"""
|
||||
table = prettytable.PrettyTable(fields, caching=False)
|
||||
table.align = 'l'
|
||||
return table
|
||||
|
||||
def print_group_members(server_group_id):
|
||||
""" Print a table detailing Server Group instances and their hypervisors """
|
||||
group_members = get_group_members(server_group_id)
|
||||
if group_members:
|
||||
table = create_table(['Instance ID', 'Instance', 'Hypervisor'])
|
||||
for server in get_group_members(server_group_id):
|
||||
instance = get_server(server)
|
||||
hypervisor = getattr(instance, 'OS-EXT-SRV-ATTR:hypervisor_hostname'.split('.')[0])
|
||||
table.add_row([instance.id, instance.name, hypervisor])
|
||||
print table
|
||||
else:
|
||||
print "Server Group", server_group_id, "empty or does not have an anti-affinity policy set."
|
||||
def get_args():
|
||||
"""
|
||||
Get commandline arguments
|
||||
"""
|
||||
parser = argparse.ArgumentParser(description='Nova Server Group anti-affinity rule checker')
|
||||
parser.add_argument('--check', type=str, help='Validate the specified Server Group')
|
||||
parser.add_argument('--list', type=str,
|
||||
help='List instances and their hypervisors for a given Server Group')
|
||||
parser.add_argument('--json', action='store_true', help='Output JSON')
|
||||
return parser.parse_args()
|
||||
|
||||
def print_group_duplicates(server_group_id):
|
||||
""" Evaluate whether any instances in a SG have been scheduled to the same hypervisor """
|
||||
group_members = get_group_members(server_group_id)
|
||||
if group_members:
|
||||
hypervisors = []
|
||||
instances = defaultdict(list)
|
||||
for instance in get_group_members(server_group_id):
|
||||
i = get_server(instance)
|
||||
hypervisor = getattr(i, 'OS-EXT-SRV-ATTR:hypervisor_hostname')
|
||||
instances[instance].append(i.name)
|
||||
instances[instance].append(hypervisor)
|
||||
hypervisors.append(hypervisor)
|
||||
dupes = [k for k, v in Counter(hypervisors).items() if v > 1]
|
||||
if dupes:
|
||||
print "Anti-affinity rules violated in Server Group:", server_group_id
|
||||
table = create_table(['Instance ID', 'Instance', 'Hypervisor'])
|
||||
[table.add_row([instance_id, instance_name, hypervisor])
|
||||
for instance_id, [instance_name, hypervisor] in instances.items()
|
||||
if hypervisor in dupes]
|
||||
print table
|
||||
else:
|
||||
print "No anti-affinity rules violated for Server Group:", server_group_id
|
||||
else:
|
||||
print "Server Group", server_group_id, "empty or does not have an anti-affinity policy set."
|
||||
def main():
|
||||
"""
|
||||
Main script
|
||||
"""
|
||||
args = get_args()
|
||||
nova_connect = NovaConnect(args)
|
||||
if args.check:
|
||||
nova_connect.print_group_duplicates(args.check)
|
||||
if args.list:
|
||||
nova_connect.print_group_members(args.list)
|
||||
|
||||
if __name__ == '__main__':
|
||||
credentials = get_credentials()
|
||||
keystone = ksclient.Client(**credentials)
|
||||
auth = v2.Password(**credentials)
|
||||
sess = session.Session(auth=auth)
|
||||
nova = nclient.Client(2, session=sess)
|
||||
args = get_args()
|
||||
group = sys.argv[2]
|
||||
if args.check:
|
||||
print_group_duplicates(group)
|
||||
if args.list:
|
||||
print_group_members(group)
|
||||
main()
|
||||
|
|
Loading…
Reference in New Issue