Merge "Support for removing hanging ports"
[functest.git] / testcases / VIM / OpenStack / CI / libraries / clean_openstack.py
1 #!/usr/bin/env python
2 #
3 # Description:
4 #   Cleans possible leftovers after running functest tests:
5 #       - Nova instances
6 #       - Glance images
7 #       - Cinder volumes
8 #       - Floating IPs
9 #       - Neutron networks, subnets and ports
10 #       - Routers
11 #       - Users and tenants
12 #
13 # Author:
14 #    jose.lausuch@ericsson.com
15 #
16
17 import argparse
18 import logging
19 import os
20 import re
21 import sys
22 import time
23
24 import novaclient.v2.client as novaclient
25 from neutronclient.v2_0 import client as neutronclient
26 from keystoneclient.v2_0 import client as keystoneclient
27 from cinderclient import client as cinderclient
28
29 parser = argparse.ArgumentParser()
30 parser.add_argument("-d", "--debug", help="Debug mode",  action="store_true")
31 args = parser.parse_args()
32
33
34 """ logging configuration """
35 logger = logging.getLogger('clean_openstack')
36 logger.setLevel(logging.DEBUG)
37
38 ch = logging.StreamHandler()
39 if args.debug:
40     ch.setLevel(logging.DEBUG)
41 else:
42     ch.setLevel(logging.INFO)
43
44 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
45 ch.setFormatter(formatter)
46 logger.addHandler(ch)
47
48 REPO_PATH=os.environ['repos_dir']+'/functest/'
49 if not os.path.exists(REPO_PATH):
50     logger.error("Functest repository directory not found '%s'" % REPO_PATH)
51     exit(-1)
52 sys.path.append(REPO_PATH + "testcases/")
53 import functest_utils
54
55 default_images = ['TestVM']
56 default_networks = ['net04', 'net04_ext', 'functest-net', 'ext-net']
57 default_routers = ['router04', 'functest-router']
58 default_users = ["heat", "heat-cfn", "cinder", "nova", "swift", "glance",
59                  "neutron", "admin", "fuel_stats_user", "quantum", "heat-cfn_heat",
60                  "ceilometer", "cinder_cinderv2", "demo"]
61 default_tenants = ["admin", "services", "service", "demo"]
62 default_security_groups = ['default']
63
64 def separator():
65     logger.debug("-------------------------------------------")
66
67 def remove_instances(nova_client):
68     logger.info("Removing Nova instances...")
69     instances = functest_utils.get_instances(nova_client)
70     if instances is None or len(instances) == 0:
71         logger.debug("No instances found.")
72         return
73
74     for instance in instances:
75         instance_name = getattr(instance, 'name')
76         instance_id = getattr(instance, 'id')
77         logger.debug("Removing instance '%s', ID=%s ..." % (instance_name,instance_id))
78         if functest_utils.delete_instance(nova_client, instance_id):
79             logger.debug("  > Done!")
80         else:
81             logger.info("  > ERROR: There has been a problem removing the "
82                         "instance %s..." % instance_id)
83
84     timeout = 50
85     while timeout > 0:
86         instances = functest_utils.get_instances(nova_client)
87         if instances is None or len(instances) == 0:
88             break
89         else:
90             logger.debug("Waiting for instances to be terminated...")
91             timeout -= 1
92             time.sleep(1)
93
94
95 def remove_images(nova_client):
96     logger.info("Removing Glance images...")
97     images = functest_utils.get_images(nova_client)
98     if images is None or len(images) == 0:
99         logger.debug("No images found.")
100         return
101
102     for image in images:
103         image_name = getattr(image, 'name')
104         image_id = getattr(image, 'id')
105         logger.debug("'%s', ID=%s " %(image_name,image_id))
106         if image_name not in default_images:
107             logger.debug("Removing image '%s', ID=%s ..." % (image_name,image_id))
108             if functest_utils.delete_glance_image(nova_client, image_id):
109                 logger.debug("  > Done!")
110             else:
111                 logger.info("  > ERROR: There has been a problem removing the"
112                             "image %s..." % image_id)
113         else:
114             logger.debug("   > this is a default image and will NOT be deleted.")
115
116
117 def remove_volumes(cinder_client):
118     logger.info("Removing Cinder volumes...")
119     volumes = functest_utils.get_volumes(cinder_client)
120     if volumes is None or len(volumes) == 0:
121         logger.debug("No volumes found.")
122         return
123
124     for volume in volumes:
125         volume_id = getattr(volume, 'id')
126         logger.debug("Removing cinder volume %s ..." % volume_id)
127         if functest_utils.delete_volume(cinder_client, volume_id):
128             logger.debug("  > Done!")
129         else:
130             logger.info("  > ERROR: There has been a problem removing the "
131                         "volume %s..." % volume_id)
132
133
134 def remove_floatingips(nova_client):
135     logger.info("Removing floating IPs...")
136     floatingips = functest_utils.get_floating_ips(nova_client)
137     if floatingips is None or len(floatingips) == 0:
138         logger.debug("No floating IPs found.")
139         return
140
141     for fip in floatingips:
142         fip_id = getattr(fip, 'id')
143         logger.debug("Removing floating IP %s ..." % fip_id)
144         if functest_utils.delete_floating_ip(nova_client, fip_id):
145             logger.debug("  > Done!")
146         else:
147             logger.info("  > ERROR: There has been a problem removing the "
148                         "floating IP %s..." % fip_id)
149
150     timeout = 50
151     while timeout > 0:
152         floatingips = functest_utils.get_floating_ips(nova_client)
153         if floatingips is None or len(floatingips) == 0:
154             break
155         else:
156             logger.debug("Waiting for floating ips to be released...")
157             timeout -= 1
158             time.sleep(1)
159
160
161 def remove_networks(neutron_client):
162     logger.info("Removing Neutron objects")
163     network_ids = []
164     networks = functest_utils.get_network_list(neutron_client)
165     if networks == None:
166         logger.debug("There are no networks in the deployment. ")
167     else:
168         logger.debug("Existing networks:")
169         for network in networks:
170             net_id = network['id']
171             net_name = network['name']
172             logger.debug(" '%s', ID=%s " %(net_name,net_id))
173             if net_name not in default_networks:
174                 logger.debug("    > this is not a default network and will be deleted.")
175                 network_ids.append(net_id)
176             else:
177                 logger.debug("   > this is a default network and will NOT be deleted.")
178
179     #delete ports
180     ports = functest_utils.get_port_list(neutron_client)
181     if ports is None:
182         logger.debug("There are no ports in the deployment. ")
183     else:
184         remove_ports(neutron_client, ports, network_ids)
185
186     #remove routers
187     routers = functest_utils.get_router_list(neutron_client)
188     if routers is None:
189         logger.debug("There are no routers in the deployment. ")
190     else:
191         remove_routers(neutron_client, routers)
192
193     #remove networks
194     if network_ids != None:
195         for net_id in network_ids:
196             logger.debug("Removing network %s ..." % net_id)
197             if functest_utils.delete_neutron_net(neutron_client, net_id):
198                 logger.debug("  > Done!")
199             else:
200                 logger.info("  > ERROR: There has been a problem removing the "
201                             "network %s..." % net_id)
202
203
204 def remove_ports(neutron_client, ports, network_ids):
205     for port in ports:
206         if port['network_id'] in network_ids:
207             port_id = port['id']
208             try:
209                 subnet_id = port['fixed_ips'][0]['subnet_id']
210             except:
211                 logger.info("  > WARNING: Port %s does not contain 'fixed_ips'" % port_id)
212                 print port
213             router_id = port['device_id']
214             if len(port['fixed_ips']) == 0 and router_id == '':
215                 logger.debug("Removing port %s ..." % port_id)
216                 if functest_utils.delete_neutron_port(neutron_client, port_id):
217                     logger.debug("  > Done!")
218                 else:
219                     logger.info("  > ERROR: There has been a problem removing the "
220                                 "port %s ..." %port_id)
221
222             elif port['device_owner'] == 'network:router_interface':
223                 logger.debug("Detaching port %s (subnet %s) from router %s ..."
224                              % (port_id,subnet_id,router_id))
225                 if functest_utils.remove_interface_router(neutron_client,
226                                                           router_id, subnet_id):
227                     time.sleep(5) # leave 5 seconds to detach before doing anything else
228                     logger.debug("  > Done!")
229                 else:
230                     logger.info("  > ERROR: There has been a problem removing the "
231                                 "interface %s from router %s..." %(subnet_id,router_id))
232             else:
233                 logger.debug("Clearing device_owner for port %s ..." % port_id)
234                 functest_utils.update_neutron_port(neutron_client,
235                                                    port_id,
236                                                    device_owner='clear')
237                 logger.debug("Removing port %s ..." % port_id)
238                 if functest_utils.delete_neutron_port(neutron_client, port_id):
239                     logger.debug("  > Done!")
240                 else:
241                     logger.debug("  > Port %s could not be removed directly" % port_id)
242
243
244 def remove_routers(neutron_client, routers):
245     for router in routers:
246         router_id = router['id']
247         router_name = router['name']
248         if router_name not in default_routers:
249             logger.debug("Checking '%s' with ID=(%s) ..." % (router_name,router_id))
250             if router['external_gateway_info'] != None:
251                 logger.debug("Router has gateway to external network. Removing link...")
252                 if functest_utils.remove_gateway_router(neutron_client, router_id):
253                     logger.debug("  > Done!")
254                 else:
255                     logger.info("  > ERROR: There has been a problem removing "
256                                 "the gateway...")
257             else:
258                 logger.debug("Router is not connected to anything. Ready to remove...")
259             logger.debug("Removing router %s(%s) ..." % (router_name, router_id))
260             if functest_utils.delete_neutron_router(neutron_client, router_id):
261                 logger.debug("  > Done!")
262             else:
263                 logger.info("  > ERROR: There has been a problem removing the "
264                             "router '%s'(%s)..." % (router_name, router_id))
265
266
267 def remove_security_groups(neutron_client):
268     logger.info("Removing Security groups...")
269     secgroups = functest_utils.get_security_groups(neutron_client)
270     if secgroups is None or len(secgroups) == 0:
271         logger.debug("No security groups found.")
272         return
273
274     for secgroup in secgroups:
275         secgroup_name = secgroup['name']
276         secgroup_id = secgroup['id']
277         logger.debug("'%s', ID=%s " %(secgroup_name,secgroup_id))
278         if secgroup_name not in default_security_groups:
279             logger.debug(" Removing '%s'..." % secgroup_name)
280             if functest_utils.delete_security_group(neutron_client, secgroup_id):
281                 logger.debug("  > Done!")
282             else:
283                 logger.info("  > ERROR: There has been a problem removing the "
284                             "security group %s..." % secgroup_id)
285         else:
286             logger.debug("   > this is a default security group and will NOT "
287                          "be deleted.")
288
289
290 def remove_users(keystone_client):
291     logger.info("Removing Users...")
292     users = functest_utils.get_users(keystone_client)
293     if users == None:
294         logger.debug("There are no users in the deployment. ")
295         return
296
297     for user in users:
298         user_name = getattr(user, 'name')
299         user_id = getattr(user, 'id')
300         logger.debug("'%s', ID=%s " %(user_name,user_id))
301         if user_name not in default_users:
302             logger.debug(" Removing '%s'..." % user_name)
303             if functest_utils.delete_user(keystone_client,user_id):
304                 logger.debug("  > Done!")
305             else:
306                 logger.info("  > ERROR: There has been a problem removing the "
307                             "user '%s'(%s)..." % (user_name,user_id))
308         else:
309             logger.debug("   > this is a default user and will NOT be deleted.")
310
311
312 def remove_tenants(keystone_client):
313     logger.info("Removing Tenants...")
314     tenants = functest_utils.get_tenants(keystone_client)
315     if tenants == None:
316         logger.debug("There are no tenants in the deployment. ")
317         return
318
319     for tenant in tenants:
320         tenant_name=getattr(tenant, 'name')
321         tenant_id = getattr(tenant, 'id')
322         logger.debug("'%s', ID=%s " %(tenant_name,tenant_id))
323         if tenant_name not in default_tenants:
324             logger.debug(" Removing '%s'..." % tenant_name)
325             if functest_utils.delete_tenant(keystone_client,tenant_id):
326                 logger.debug("  > Done!")
327             else:
328                 logger.info("  > ERROR: There has been a problem removing the "
329                             "tenant '%s'(%s)..." % (tenant_name,tenant_id))
330         else:
331             logger.debug("   > this is a default tenant and will NOT be deleted.")
332
333
334
335 def main():
336     creds_nova = functest_utils.get_credentials("nova")
337     nova_client = novaclient.Client(**creds_nova)
338
339     creds_neutron = functest_utils.get_credentials("neutron")
340     neutron_client = neutronclient.Client(**creds_neutron)
341
342     creds_keystone = functest_utils.get_credentials("keystone")
343     keystone_client = keystoneclient.Client(**creds_keystone)
344
345     creds_cinder = functest_utils.get_credentials("cinder")
346     #cinder_client = cinderclient.Client(**creds_cinder)
347     cinder_client = cinderclient.Client('1',creds_cinder['username'],
348                                         creds_cinder['api_key'],
349                                         creds_cinder['project_id'],
350                                         creds_cinder['auth_url'],
351                                         service_type="volume")
352
353     if not functest_utils.check_credentials():
354         logger.error("Please source the openrc credentials and run the script again.")
355         exit(-1)
356
357
358     remove_instances(nova_client)
359     separator()
360     remove_images(nova_client)
361     separator()
362     remove_volumes(cinder_client)
363     separator()
364     remove_floatingips(nova_client)
365     separator()
366     remove_networks(neutron_client)
367     separator()
368     remove_security_groups(neutron_client)
369     separator()
370     remove_users(keystone_client)
371     separator()
372     remove_tenants(keystone_client)
373     separator()
374
375     exit(0)
376
377
378 if __name__ == '__main__':
379     main()