6b13f69a365e6ffc9bb4ef1d7db8913a8deb2d28
[nfvbench.git] / nfvbench / cleanup.py
1 #!/usr/bin/env python
2 # Copyright 2017 Cisco Systems, Inc.  All rights reserved.
3 #
4 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
5 #    not use this file except in compliance with the License. You may obtain
6 #    a copy of the License at
7 #
8 #         http://www.apache.org/licenses/LICENSE-2.0
9 #
10 #    Unless required by applicable law or agreed to in writing, software
11 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 #    License for the specific language governing permissions and limitations
14 #    under the License.
15 #
16
17 import sys
18 import time
19
20 from neutronclient.neutron import client as nclient
21 from novaclient.client import Client
22 from novaclient.exceptions import NotFound
23 from tabulate import tabulate
24
25 import credentials as credentials
26 from log import LOG
27
28 class ComputeCleaner(object):
29     """A cleaner for compute resources."""
30
31     def __init__(self, nova_client, instance_prefix):
32         self.nova_client = nova_client
33         LOG.info('Discovering instances %s...', instance_prefix)
34         all_servers = self.nova_client.servers.list()
35         self.servers = [server for server in all_servers
36                         if server.name.startswith(instance_prefix)]
37
38     def instance_exists(self, server):
39         try:
40             self.nova_client.servers.get(server.id)
41         except NotFound:
42             return False
43         return True
44
45     def get_resource_list(self):
46         return [["Instance", server.name, server.id] for server in self.servers]
47
48     def clean(self):
49         if self.servers:
50             for server in self.servers:
51                 try:
52                     LOG.info('Deleting instance %s...', server.name)
53                     self.nova_client.servers.delete(server.id)
54                 except Exception:
55                     LOG.exception("Instance %s deletion failed", server.name)
56             LOG.info('    Waiting for %d instances to be fully deleted...', len(self.servers))
57             retry_count = 15 + len(self.servers) * 5
58             while True:
59                 retry_count -= 1
60                 self.servers = [server for server in self.servers if self.instance_exists(server)]
61                 if not self.servers:
62                     break
63
64                 if retry_count:
65                     LOG.info('    %d yet to be deleted by Nova, retries left=%d...',
66                              len(self.servers), retry_count)
67                     time.sleep(2)
68                 else:
69                     LOG.warning('    instance deletion verification time-out: %d still not deleted',
70                                 len(self.servers))
71                     break
72
73
74 class NetworkCleaner(object):
75     """A cleaner for network resources."""
76
77     def __init__(self, neutron_client, network_name_prefixes):
78         self.neutron_client = neutron_client
79         LOG.info('Discovering networks...')
80         all_networks = self.neutron_client.list_networks()['networks']
81         self.networks = []
82         net_ids = []
83         for net in all_networks:
84             netname = net['name']
85             for prefix in network_name_prefixes:
86                 if netname.startswith(prefix):
87                     self.networks.append(net)
88                     net_ids.append(net['id'])
89                     break
90         if net_ids:
91             LOG.info('Discovering ports...')
92             all_ports = self.neutron_client.list_ports()['ports']
93             self.ports = [port for port in all_ports if port['network_id'] in net_ids]
94         else:
95             self.ports = []
96
97     def get_resource_list(self):
98         res_list = [["Network", net['name'], net['id']] for net in self.networks]
99         res_list.extend([["Port", port['name'], port['id']] for port in self.ports])
100         return res_list
101
102     def clean(self):
103         for port in self.ports:
104             LOG.info("Deleting port %s...", port['id'])
105             try:
106                 self.neutron_client.delete_port(port['id'])
107             except Exception:
108                 LOG.exception("Port deletion failed")
109
110         # associated subnets are automatically deleted by neutron
111         for net in self.networks:
112             LOG.info("Deleting network %s...", net['name'])
113             try:
114                 self.neutron_client.delete_network(net['id'])
115             except Exception:
116                 LOG.exception("Network deletion failed")
117
118 class FlavorCleaner(object):
119     """Cleaner for NFVbench flavor."""
120
121     def __init__(self, nova_client, name):
122         self.name = name
123         LOG.info('Discovering flavor %s...', name)
124         try:
125             self.flavor = nova_client.flavors.find(name=name)
126         except NotFound:
127             self.flavor = None
128
129     def get_resource_list(self):
130         if self.flavor:
131             return [['Flavor', self.name, self.flavor.id]]
132         return None
133
134     def clean(self):
135         if self.flavor:
136             LOG.info("Deleting flavor %s...", self.flavor.name)
137             try:
138                 self.flavor.delete()
139             except Exception:
140                 LOG.exception("Flavor deletion failed")
141
142 class Cleaner(object):
143     """Cleaner for all NFVbench resources."""
144
145     def __init__(self, config):
146         cred = credentials.Credentials(config.openrc_file, None, False)
147         session = cred.get_session()
148         self.neutron_client = nclient.Client('2.0', session=session)
149         self.nova_client = Client(2, session=session)
150         network_names = [inet['name'] for inet in config.internal_networks.values()]
151         # add idle networks as well
152         if config.idle_networks.name:
153             network_names.append(config.idle_networks.name)
154         self.cleaners = [ComputeCleaner(self.nova_client, config.loop_vm_name),
155                          FlavorCleaner(self.nova_client, config.flavor_type),
156                          NetworkCleaner(self.neutron_client, network_names)]
157
158     def show_resources(self):
159         """Show all NFVbench resources."""
160         table = [["Type", "Name", "UUID"]]
161         for cleaner in self.cleaners:
162             res_list = cleaner.get_resource_list()
163             if res_list:
164                 table.extend(res_list)
165         count = len(table) - 1
166         if count:
167             LOG.info('Discovered %d NFVbench resources:\n%s', count,
168                      tabulate(table, headers="firstrow", tablefmt="psql"))
169         else:
170             LOG.info('No matching NFVbench resources found')
171         return count
172
173     def clean(self, prompt):
174         """Clean all resources."""
175         LOG.info("NFVbench will delete all resources shown...")
176         if prompt:
177             answer = raw_input("Are you sure? (y/n) ")
178             if answer.lower() != 'y':
179                 LOG.info("Exiting without deleting any resource")
180                 sys.exit(0)
181         for cleaner in self.cleaners:
182             cleaner.clean()