194 lines
7.6 KiB
Python
Executable File
194 lines
7.6 KiB
Python
Executable File
#!/usr/bin/python
|
|
"""
|
|
Author: amos.steven.davis@hp.com
|
|
Description: Fix nova quota in the nova database when the acutal usage
|
|
and what nova thinks is the quota do not match.
|
|
"""
|
|
from nova import db
|
|
from nova import config
|
|
from nova import context
|
|
from collections import OrderedDict
|
|
import argparse
|
|
import prettytable
|
|
|
|
|
|
def make_table(name, *args):
|
|
q = prettytable.PrettyTable(name)
|
|
q.align = "c"
|
|
q.add_row(args[0])
|
|
return q
|
|
|
|
|
|
def get_actual_usage(cntxt, tenant):
|
|
instance_info = db.instance_data_get_for_project(cxt, tenant)
|
|
|
|
# calculate actual usage
|
|
actual_instance_count = instance_info[0]
|
|
actual_core_count = instance_info[1]
|
|
actual_ram_count = instance_info[2]
|
|
|
|
# actual_fixed_ips should be the same as actual_instance_count since there is no
|
|
# reason in our environment for someone to use two fixed IPs per instance
|
|
# db.fixed_ip_count_by_project(cxt,tenant)
|
|
actual_fixed_ips = actual_instance_count
|
|
actual_secgroup_count = db.security_group_count_by_project(cxt, tenant)
|
|
|
|
return OrderedDict((
|
|
("actual_instance_count", actual_instance_count),
|
|
("actual_core_count", actual_core_count),
|
|
("actual_ram_count", actual_ram_count),
|
|
("actual_fixed_ips", actual_fixed_ips),
|
|
("actual_secgroup_count", actual_secgroup_count)
|
|
))
|
|
|
|
|
|
def get_incorrect_usage(cntxt, tenant):
|
|
existing_usage = db.quota_usage_get_all_by_project(cntxt, tenant)
|
|
# {u'ram': {'reserved': 0L, 'in_use': 0L},
|
|
# u'floating_ips': {'reserved': 0L, 'in_use': 1L},
|
|
# u'instances': {'reserved': 0L, 'in_use': 0L},
|
|
# u'cores': {'reserved': 0L, 'in_use': 0L},
|
|
# 'project_id': tenant,
|
|
# u'fixed_ips': {'reserved': 0L, 'in_use': 0L},
|
|
# u'security_groups': {'reserved': 0L, 'in_use': 1L}}
|
|
#
|
|
# Get (instance_count, total_cores, total_ram) for project.
|
|
# If instances does not exist, then this
|
|
if 'instances' in existing_usage:
|
|
# it's possible for accounts to use nothing but the system default
|
|
# group, which doesn't get tracked, so default to 1
|
|
try:
|
|
security_groups = existing_usage["security_groups"]["in_use"]
|
|
except KeyError:
|
|
security_groups = 1
|
|
|
|
return OrderedDict((
|
|
("db_instance_count", existing_usage["instances"]["in_use"]),
|
|
("db_core_count", existing_usage["cores"]["in_use"]),
|
|
("db_ram_count", existing_usage["ram"]["in_use"]),
|
|
("db_fixed_ips", existing_usage["fixed_ips"]["in_use"]),
|
|
("db_secgroup_count", security_groups)
|
|
))
|
|
else:
|
|
print "%s get_incorrect_usage failed to find quota usage information in " \
|
|
"database. Is this tenant in use?" % tenant
|
|
exit(0)
|
|
|
|
|
|
def fix_usage(cntxt, tenant, actual_table_name, incorrect_table_name):
|
|
print "\nUpdating quota usage to reflect actual usage..\n"
|
|
# Calculate differences
|
|
existing_usage = db.quota_usage_get_all_by_project(cntxt, tenant)
|
|
actual = get_actual_usage(cntxt, tenant)
|
|
|
|
# it's possible for accounts to use nothing but the system default
|
|
# group, which doesn't get tracked, so default to 0
|
|
try:
|
|
security_groups = existing_usage["security_groups"]["in_use"]
|
|
secgroup_difference = security_groups - actual["actual_secgroup_count"]
|
|
except KeyError:
|
|
security_groups = None
|
|
|
|
instance_difference = \
|
|
existing_usage["instances"]["in_use"] - actual["actual_instance_count"]
|
|
core_difference = \
|
|
existing_usage["cores"]["in_use"] - actual["actual_core_count"]
|
|
ram_difference = \
|
|
existing_usage["ram"]["in_use"] - actual["actual_ram_count"]
|
|
# Actual_fixed_ips should be the same as actual_instance_count since there is no
|
|
# Reason in our environment for someone to use two fixed IPs
|
|
# existing_usage["fixed_ips"]["in_use"]-actual["actual_fixed_ips"]
|
|
fixedips_difference = \
|
|
existing_usage["fixed_ips"]["in_use"] - actual["actual_instance_count"]
|
|
# Quota_usage_update(context, project_id, resource, **kwargs)
|
|
# Update ram.
|
|
db.quota_usage_update(cxt,
|
|
tenant,
|
|
'ram',
|
|
in_use=existing_usage["ram"]["in_use"] -
|
|
ram_difference)
|
|
# Update instances
|
|
db.quota_usage_update(cxt,
|
|
tenant,
|
|
'instances',
|
|
in_use=existing_usage["instances"]["in_use"] -
|
|
instance_difference)
|
|
# Update cores
|
|
db.quota_usage_update(cxt,
|
|
tenant,
|
|
'cores',
|
|
in_use=existing_usage["cores"]["in_use"] - core_difference)
|
|
# Update fixed IPs
|
|
"""
|
|
db.quota_usage_update(cxt,
|
|
tenant,
|
|
'fixed_ips',
|
|
in_use=existing_usage["fixed_ips"]["in_use"] - fixedips_difference)
|
|
"""
|
|
|
|
# Update security groups
|
|
if security_groups is not None:
|
|
db.quota_usage_update(cxt,
|
|
tenant,
|
|
'security_groups',
|
|
in_use=security_groups - secgroup_difference)
|
|
|
|
print "############### Actual Usage (including non-active instances) ###############"
|
|
print make_table(actual_table_name, get_actual_usage(cxt, tenant).values())
|
|
print "############### Corrected Database Usage ###############"
|
|
print make_table(incorrect_table_name, get_incorrect_usage(cxt, tenant).values())
|
|
|
|
|
|
actual_table_name = ["Actual Instances",
|
|
"Actual Cores",
|
|
"Actual RAM",
|
|
"Actual Fixed_ips",
|
|
"Actual Security_Groups"]
|
|
|
|
# these are spaced so that the Quota & DB tables match in size
|
|
incorrect_table_name = [" DB Instances ",
|
|
" DB Cores ",
|
|
" DB RAM ",
|
|
" DB Fixed_ips ",
|
|
" DB Security_Groups "]
|
|
|
|
config.parse_args(['filename', '--config-file', '/etc/nova/nova.conf'])
|
|
|
|
# Get other arguments
|
|
parser = argparse.ArgumentParser(
|
|
description='Fix quota differences between reality and the database')
|
|
parser.add_argument('--tenant', help='Specify tenant', required=True)
|
|
parser.add_argument('-n', '--dryrun', help='Dry Run - don\'t update the database',
|
|
action="store_true")
|
|
args = parser.parse_args()
|
|
tenant = args.tenant
|
|
|
|
# Get admin context
|
|
cxt = context.get_admin_context()
|
|
|
|
print "############### Actual Usage (including non-active instances) ###############"
|
|
print make_table(actual_table_name, get_actual_usage(cxt, tenant).values())
|
|
print "############### Database Usage ###############"
|
|
print make_table(incorrect_table_name, get_incorrect_usage(cxt, tenant).values())
|
|
|
|
# if the actual usage & the quota tracking differ,
|
|
# update quota to match reality
|
|
if get_incorrect_usage(cxt, tenant).values() == get_actual_usage(cxt, tenant).values():
|
|
print "\n%s quota is OK" % tenant
|
|
elif args.dryrun:
|
|
print "Dry Run Mode Enabled - not correcting the quota database."
|
|
else:
|
|
fix_usage(cxt, tenant, actual_table_name, incorrect_table_name)
|
|
|
|
# This section can replace the final if/else statement to allow prompting for
|
|
# each tenant before changes happen
|
|
# if get_incorrect_usage(cxt,tenant).values() == get_actual_usage(cxt,tenant).values():
|
|
# print "%s quota is OK" % tenant
|
|
# else:
|
|
# if raw_input("Enter 'YES' to make the Database Usage match the Actual Usage. " \
|
|
# "This will modify the Nova database: ") != "YES":
|
|
# print "Exiting."
|
|
# exit(0)
|
|
# else:
|
|
# fix_usage(cxt,tenant,actual_table_name,incorrect_table_name)
|