Add cleanup action
We can use fuel-devops for deletion of outdated environment. Usage: dos.py show-old 3d dos.py erase-old 3d where "3d" is time-to-live interval. All envs older than given interval will be erased. Last char of interval is multiplier, could be: - s: seconds - m: minutes - h: hours - d: days erase-old operation is interactive but it could be disabled via "--force-cleanup" arg. list-old command supports --timestamps arg. Note that devops uses UTC timestamps! Change-Id: Ic1a744996495296e22ae0fdef9752dba8790aac8
This commit is contained in:
parent
887368db3b
commit
3ac4e8fc7b
136
devops/shell.py
136
devops/shell.py
|
@ -19,8 +19,11 @@ import collections
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import datetime
|
||||||
import tabulate
|
import tabulate
|
||||||
|
|
||||||
|
from six.moves import input
|
||||||
|
|
||||||
import devops
|
import devops
|
||||||
from devops import client
|
from devops import client
|
||||||
from devops import error
|
from devops import error
|
||||||
|
@ -53,10 +56,53 @@ class Shell(object):
|
||||||
print(tabulate.tabulate(columns, headers=headers,
|
print(tabulate.tabulate(columns, headers=headers,
|
||||||
tablefmt="simple"))
|
tablefmt="simple"))
|
||||||
|
|
||||||
def do_list(self):
|
@staticmethod
|
||||||
env_names = self.client.list_env_names()
|
def query_yes_no(question, default=None):
|
||||||
|
"""Ask a yes/no question via standard input and return the answer.
|
||||||
|
|
||||||
|
If invalid input is given, the user will be asked until
|
||||||
|
they acutally give valid input.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
question(str):
|
||||||
|
A question that is presented to the user.
|
||||||
|
default(bool|None):
|
||||||
|
The default value when enter is pressed with no value.
|
||||||
|
When None, there is no default value and the query
|
||||||
|
will loop.
|
||||||
|
Returns:
|
||||||
|
A bool indicating whether user has entered yes or no.
|
||||||
|
|
||||||
|
Side Effects:
|
||||||
|
Blocks program execution until valid input(y/n) is given.
|
||||||
|
"""
|
||||||
|
yes_list = ["yes", "y"]
|
||||||
|
no_list = ["no", "n"]
|
||||||
|
|
||||||
|
default_dict = { # default => prompt default string
|
||||||
|
None: "[y/n]",
|
||||||
|
True: "[Y/n]",
|
||||||
|
False: "[y/N]",
|
||||||
|
}
|
||||||
|
default_str = default_dict[default]
|
||||||
|
prompt_str = "{} {} ".format(question, default_str)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
choice = input(prompt_str).lower()
|
||||||
|
|
||||||
|
if not choice and default is not None:
|
||||||
|
return default
|
||||||
|
if choice in yes_list:
|
||||||
|
return True
|
||||||
|
if choice in no_list:
|
||||||
|
return False
|
||||||
|
|
||||||
|
notification_str = "Please respond with 'y' or 'n'"
|
||||||
|
print(notification_str)
|
||||||
|
|
||||||
|
def print_envs_table(self, env_names_list):
|
||||||
columns = []
|
columns = []
|
||||||
for env_name in sorted(env_names):
|
for env_name in sorted(env_names_list):
|
||||||
env = self.client.get_env(env_name)
|
env = self.client.get_env(env_name)
|
||||||
column = collections.OrderedDict()
|
column = collections.OrderedDict()
|
||||||
column['NAME'] = env.name
|
column['NAME'] = env.name
|
||||||
|
@ -72,6 +118,9 @@ class Shell(object):
|
||||||
|
|
||||||
self.print_table(headers='keys', columns=columns)
|
self.print_table(headers='keys', columns=columns)
|
||||||
|
|
||||||
|
def do_list(self):
|
||||||
|
self.print_envs_table(self.client.list_env_names())
|
||||||
|
|
||||||
def do_show(self):
|
def do_show(self):
|
||||||
nodes = sorted(self.env.get_nodes(), key=lambda node: node.name)
|
nodes = sorted(self.env.get_nodes(), key=lambda node: node.name)
|
||||||
headers = ("VNC", "NODE-NAME", "GROUP-NAME")
|
headers = ("VNC", "NODE-NAME", "GROUP-NAME")
|
||||||
|
@ -131,6 +180,58 @@ class Shell(object):
|
||||||
def do_erase(self):
|
def do_erase(self):
|
||||||
self.env.erase()
|
self.env.erase()
|
||||||
|
|
||||||
|
def get_lifetime_delta(self):
|
||||||
|
data = self.params.env_lifetime
|
||||||
|
multipliers = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}
|
||||||
|
if data[-1] not in multipliers:
|
||||||
|
raise ValueError(
|
||||||
|
'Value should end with '
|
||||||
|
'one of "{}", got "{}"'.format(
|
||||||
|
" ".join(multipliers.keys()), data
|
||||||
|
))
|
||||||
|
num = int(data[:-1])
|
||||||
|
mul = data[-1]
|
||||||
|
return datetime.timedelta(seconds=num*multipliers[mul])
|
||||||
|
|
||||||
|
def get_old_environments(self):
|
||||||
|
delta = self.get_lifetime_delta()
|
||||||
|
# devops uses utc timestamps for BaseModel
|
||||||
|
timestamp_now = datetime.datetime.utcnow()
|
||||||
|
envs_to_erase = []
|
||||||
|
for env_name in client.DevopsClient.list_env_names():
|
||||||
|
env = client.DevopsClient.get_env(env_name)
|
||||||
|
if (timestamp_now - env.created) > delta:
|
||||||
|
envs_to_erase.append(env)
|
||||||
|
return envs_to_erase
|
||||||
|
|
||||||
|
def do_erase_old(self):
|
||||||
|
envs_to_erase = self.get_old_environments()
|
||||||
|
|
||||||
|
for env in envs_to_erase:
|
||||||
|
print("Env '{}' will be erased!".format(env.name))
|
||||||
|
|
||||||
|
if envs_to_erase:
|
||||||
|
if not self.params.force_cleanup:
|
||||||
|
answer = self.query_yes_no(
|
||||||
|
"The cleanup operation is destructive one, "
|
||||||
|
"all environments listed above will be erased. "
|
||||||
|
"DELETION CAN NOT BE UNDONE! Proceed? ",
|
||||||
|
default=False)
|
||||||
|
if not answer:
|
||||||
|
print("Wise choice, aborting...")
|
||||||
|
sys.exit(0)
|
||||||
|
else:
|
||||||
|
print("Nothing to erase, exiting...")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
for env in envs_to_erase:
|
||||||
|
print("Erasing '{}'...".format(env.name))
|
||||||
|
env.erase()
|
||||||
|
|
||||||
|
def do_list_old(self):
|
||||||
|
env_names = [env.name for env in self.get_old_environments()]
|
||||||
|
self.print_envs_table(env_names)
|
||||||
|
|
||||||
def do_start(self):
|
def do_start(self):
|
||||||
self.env.start()
|
self.env.start()
|
||||||
|
|
||||||
|
@ -475,6 +576,22 @@ class Shell(object):
|
||||||
'If set to 0, the disk will not be '
|
'If set to 0, the disk will not be '
|
||||||
'allocated',
|
'allocated',
|
||||||
default=50, type=int)
|
default=50, type=int)
|
||||||
|
|
||||||
|
force_cleanup_parser = argparse.ArgumentParser(add_help=False)
|
||||||
|
force_cleanup_parser.add_argument(
|
||||||
|
'--force-cleanup',
|
||||||
|
dest='force_cleanup',
|
||||||
|
action='store_const', const=True,
|
||||||
|
help='Do not ask confirmation for cleanup action.',
|
||||||
|
default=False)
|
||||||
|
|
||||||
|
env_lifetime = argparse.ArgumentParser(add_help=False)
|
||||||
|
env_lifetime.add_argument(
|
||||||
|
dest='env_lifetime',
|
||||||
|
help='Erase environments older than given time interval. '
|
||||||
|
'Example:"45m", "12h", "3d"',
|
||||||
|
default="", type=str)
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
description="Manage virtual environments. "
|
description="Manage virtual environments. "
|
||||||
"For additional help, use with -h/--help option")
|
"For additional help, use with -h/--help option")
|
||||||
|
@ -485,6 +602,19 @@ class Shell(object):
|
||||||
parents=[list_ips_parser, timestamps_parser],
|
parents=[list_ips_parser, timestamps_parser],
|
||||||
help="Show virtual environments",
|
help="Show virtual environments",
|
||||||
description="Show virtual environments on host")
|
description="Show virtual environments on host")
|
||||||
|
subparsers.add_parser('erase-old',
|
||||||
|
parents=[force_cleanup_parser,
|
||||||
|
env_lifetime],
|
||||||
|
help="Cleanup old virtual environments",
|
||||||
|
description="Cleanup virtual environments on "
|
||||||
|
"host")
|
||||||
|
subparsers.add_parser('list-old',
|
||||||
|
parents=[env_lifetime, list_ips_parser,
|
||||||
|
timestamps_parser],
|
||||||
|
help="Show virtual environments older than given"
|
||||||
|
" lifetime interval",
|
||||||
|
description="Show old virtual "
|
||||||
|
"environments on host")
|
||||||
subparsers.add_parser('show', parents=[name_parser],
|
subparsers.add_parser('show', parents=[name_parser],
|
||||||
help="Show VMs in environment",
|
help="Show VMs in environment",
|
||||||
description="Show VMs in environment")
|
description="Show VMs in environment")
|
||||||
|
|
Loading…
Reference in New Issue