X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=nfvbench%2Fcleanup.py;h=6cb27138f489d4d8f97e12049d567d07ab183e61;hb=ce2525c2a621af3d20fc58f03a8f88d29e0e3617;hp=819514adf9864df38382e3b47cc0152246d90257;hpb=391dcf76fefb747888a3411ae3b8df7b1ad26685;p=nfvbench.git diff --git a/nfvbench/cleanup.py b/nfvbench/cleanup.py index 819514a..6cb2713 100644 --- a/nfvbench/cleanup.py +++ b/nfvbench/cleanup.py @@ -22,8 +22,9 @@ from novaclient.client import Client from novaclient.exceptions import NotFound from tabulate import tabulate -import credentials as credentials -from log import LOG +from . import credentials +from .log import LOG + class ComputeCleaner(object): """A cleaner for compute resources.""" @@ -45,30 +46,42 @@ class ComputeCleaner(object): def get_resource_list(self): return [["Instance", server.name, server.id] for server in self.servers] - def clean(self): - if self.servers: - for server in self.servers: - try: - LOG.info('Deleting instance %s...', server.name) - self.nova_client.servers.delete(server.id) - except Exception: - LOG.exception("Instance %s deletion failed", server.name) - LOG.info(' Waiting for %d instances to be fully deleted...', len(self.servers)) - retry_count = 15 + len(self.servers) * 5 - while True: - retry_count -= 1 - self.servers = [server for server in self.servers if self.instance_exists(server)] - if not self.servers: - break + def get_cleaner_code(self): + return "instances" - if retry_count: - LOG.info(' %d yet to be deleted by Nova, retries left=%d...', - len(self.servers), retry_count) - time.sleep(2) - else: - LOG.warning(' instance deletion verification time-out: %d still not deleted', - len(self.servers)) - break + def clean_needed(self, clean_options): + if clean_options is None: + return True + code = self.get_cleaner_code() + return code[0] in clean_options + + def clean(self, clean_options): + if self.clean_needed(clean_options): + if self.servers: + for server in self.servers: + try: + LOG.info('Deleting instance %s...', server.name) + self.nova_client.servers.delete(server.id) + except Exception: + LOG.exception("Instance %s deletion failed", server.name) + LOG.info(' Waiting for %d instances to be fully deleted...', len(self.servers)) + retry_count = 15 + len(self.servers) * 5 + while True: + retry_count -= 1 + self.servers = [server for server in self.servers if + self.instance_exists(server)] + if not self.servers: + break + + if retry_count: + LOG.info(' %d yet to be deleted by Nova, retries left=%d...', + len(self.servers), retry_count) + time.sleep(2) + else: + LOG.warning( + ' instance deletion verification time-out: %d still not deleted', + len(self.servers)) + break class NetworkCleaner(object): @@ -83,7 +96,7 @@ class NetworkCleaner(object): for net in all_networks: netname = net['name'] for prefix in network_name_prefixes: - if netname.startswith(prefix): + if prefix and netname.startswith(prefix): self.networks.append(net) net_ids.append(net['id']) break @@ -91,28 +104,125 @@ class NetworkCleaner(object): LOG.info('Discovering ports...') all_ports = self.neutron_client.list_ports()['ports'] self.ports = [port for port in all_ports if port['network_id'] in net_ids] + LOG.info('Discovering floating ips...') + all_floating_ips = self.neutron_client.list_floatingips()['floatingips'] + self.floating_ips = [floating_ip for floating_ip in all_floating_ips if + floating_ip['floating_network_id'] in net_ids and "nfvbench" in + floating_ip['description']] else: self.ports = [] + self.floating_ips = [] def get_resource_list(self): res_list = [["Network", net['name'], net['id']] for net in self.networks] res_list.extend([["Port", port['name'], port['id']] for port in self.ports]) + res_list.extend( + [["Floating IP", floating_ip['description'], floating_ip['id']] for floating_ip in + self.floating_ips]) return res_list - def clean(self): - for port in self.ports: - LOG.info("Deleting port %s...", port['id']) - try: - self.neutron_client.delete_port(port['id']) - except Exception: - LOG.exception("Port deletion failed") - - for net in self.networks: - LOG.info("Deleting network %s...", net['name']) - try: - self.neutron_client.delete_network(net['id']) - except Exception: - LOG.exception("Network deletion failed") + def get_cleaner_code(self): + return "networks, ports and floating ips" + + def clean_needed(self, clean_options): + if clean_options is None: + return True + code = self.get_cleaner_code() + return code[0] in clean_options + + def clean(self, clean_options): + if self.clean_needed(clean_options): + for port in self.ports: + LOG.info("Deleting port %s...", port['id']) + try: + self.neutron_client.delete_port(port['id']) + except Exception: + LOG.exception("Port deletion failed") + for floating_ip in self.floating_ips: + LOG.info("Deleting floating ip %s...", floating_ip['id']) + try: + self.neutron_client.delete_floatingip(floating_ip['id']) + except Exception: + LOG.exception("Floating IP deletion failed") + # associated subnets are automatically deleted by neutron + for net in self.networks: + LOG.info("Deleting network %s...", net['name']) + try: + self.neutron_client.delete_network(net['id']) + except Exception: + LOG.exception("Network deletion failed") + + +class RouterCleaner(object): + """A cleaner for router resources.""" + + def __init__(self, neutron_client, router_names): + self.neutron_client = neutron_client + LOG.info('Discovering routers...') + all_routers = self.neutron_client.list_routers()['routers'] + self.routers = [] + self.ports = [] + self.routes = [] + rtr_ids = [] + for rtr in all_routers: + rtrname = rtr['name'] + for name in router_names: + if rtrname == name: + self.routers.append(rtr) + rtr_ids.append(rtr['id']) + + LOG.info('Discovering router routes for router %s...', rtr['name']) + all_routes = rtr['routes'] + for route in all_routes: + LOG.info("destination: %s, nexthop: %s", route['destination'], + route['nexthop']) + + LOG.info('Discovering router ports for router %s...', rtr['name']) + self.ports.extend(self.neutron_client.list_ports(device_id=rtr['id'])['ports']) + break + + def get_resource_list(self): + res_list = [["Router", rtr['name'], rtr['id']] for rtr in self.routers] + return res_list + + def get_cleaner_code(self): + return "router" + + def clean_needed(self, clean_options): + if clean_options is None: + return True + code = self.get_cleaner_code() + return code[0] in clean_options + + def clean(self, clean_options): + if self.clean_needed(clean_options): + # associated routes needs to be deleted before deleting routers + for rtr in self.routers: + LOG.info("Deleting routes for %s...", rtr['name']) + try: + body = { + 'router': { + 'routes': [] + } + } + self.neutron_client.update_router(rtr['id'], body) + except Exception: + LOG.exception("Router routes deletion failed") + LOG.info("Deleting ports for %s...", rtr['name']) + try: + for port in self.ports: + body = { + 'port_id': port['id'] + } + self.neutron_client.remove_interface_router(rtr['id'], body) + except Exception: + LOG.exception("Router ports deletion failed") + LOG.info("Deleting router %s...", rtr['name']) + try: + self.neutron_client.delete_router(rtr['id']) + except Exception: + LOG.exception("Router deletion failed") + class FlavorCleaner(object): """Cleaner for NFVbench flavor.""" @@ -130,13 +240,24 @@ class FlavorCleaner(object): return [['Flavor', self.name, self.flavor.id]] return None - def clean(self): - if self.flavor: - LOG.info("Deleting flavor %s...", self.flavor.name) - try: - self.flavor.delete() - except Exception: - LOG.exception("Flavor deletion failed") + def get_cleaner_code(self): + return "flavor" + + def clean_needed(self, clean_options): + if clean_options is None: + return True + code = self.get_cleaner_code() + return code[0] in clean_options + + def clean(self, clean_options): + if self.clean_needed(clean_options): + if self.flavor: + LOG.info("Deleting flavor %s...", self.flavor.name) + try: + self.flavor.delete() + except Exception: + LOG.exception("Flavor deletion failed") + class Cleaner(object): """Cleaner for all NFVbench resources.""" @@ -147,9 +268,17 @@ class Cleaner(object): self.neutron_client = nclient.Client('2.0', session=session) self.nova_client = Client(2, session=session) network_names = [inet['name'] for inet in config.internal_networks.values()] + network_names.extend([inet['name'] for inet in config.edge_networks.values()]) + network_names.append(config.management_network['name']) + network_names.append(config.floating_network['name']) + router_names = [rtr['router_name'] for rtr in config.edge_networks.values()] + # add idle networks as well + if config.idle_networks.name: + network_names.append(config.idle_networks.name) self.cleaners = [ComputeCleaner(self.nova_client, config.loop_vm_name), FlavorCleaner(self.nova_client, config.flavor_type), - NetworkCleaner(self.neutron_client, network_names)] + NetworkCleaner(self.neutron_client, network_names), + RouterCleaner(self.neutron_client, router_names)] def show_resources(self): """Show all NFVbench resources.""" @@ -168,11 +297,37 @@ class Cleaner(object): def clean(self, prompt): """Clean all resources.""" - LOG.info("NFVbench will delete all resources shown...") + LOG.info("NFVbench will delete resources shown...") + clean_options = None if prompt: - answer = raw_input("Are you sure? (y/n) ") + answer = input("Do you want to delete all ressources? (y/n) ") if answer.lower() != 'y': - LOG.info("Exiting without deleting any resource") - sys.exit(0) + print("What kind of resources do you want to delete?") + all_option = "" + all_option_codes = [] + for cleaner in self.cleaners: + code = cleaner.get_cleaner_code() + print(("%s: %s" % (code[0], code))) + all_option += code[0] + all_option_codes.append(code) + print(("a: all resources - a shortcut for '%s'" % all_option)) + all_option_codes.append("all resources") + print("q: quit") + answer_res = input(":").lower() + # Check only first character because answer_res can be "flavor" and it is != all + if answer_res[0] == "a": + clean_options = all_option + elif answer_res[0] != 'q': + # if user write complete code instead of shortcuts + # Get only first character of clean code to avoid false clean request + # i.e "networks and ports" and "router" have 1 letter in common and router clean + # will be called even if user ask for networks and ports + if answer_res in all_option_codes: + clean_options = answer_res[0] + else: + clean_options = answer_res + else: + LOG.info("Exiting without deleting any resource") + sys.exit(0) for cleaner in self.cleaners: - cleaner.clean() + cleaner.clean(clean_options)