blob: 495469f4adf2d28a64b4bbebae8b08a00a3c8e7d [file] [log] [blame]
Sapan Bhatiaf68688d2013-09-03 11:45:46 -04001import os
2import base64
Tony Macka76b8952013-10-05 23:36:30 -04003import traceback
4from collections import defaultdict
Tony Mackae7f30c2013-09-25 12:46:50 -04005from django.db.models import F, Q
Sapan Bhatiaf68688d2013-09-03 11:45:46 -04006from planetstack.config import Config
Tony Macka76b8952013-10-05 23:36:30 -04007from util.logger import Logger, logging
Tony Mack66646d52013-09-24 21:47:12 -04008from observer.openstacksyncstep import OpenStackSyncStep
Tony Macke4be32f2014-03-11 20:45:25 -04009from deployment_auth import deployment_auth
Tony Macka76b8952013-10-05 23:36:30 -040010from core.models import *
11
Andy Bavier04111b72013-10-22 16:47:10 -040012logger = Logger(level=logging.INFO)
Sapan Bhatiaf68688d2013-09-03 11:45:46 -040013
Tony Mack66646d52013-09-24 21:47:12 -040014class GarbageCollector(OpenStackSyncStep):
15 requested_interval = 86400
16 provides=[]
Sapan Bhatiaf68688d2013-09-03 11:45:46 -040017
Tony Mackb0e03bf2013-10-05 20:52:13 -040018 def call(self, **args):
Tony Mack387a73f2013-09-18 07:59:14 -040019 try:
Tony Macke1509e82013-10-09 12:38:04 -040020 #self.gc_roles()
Tony Mackfccb9eb2014-04-14 22:16:42 -040021 #self.gc_tenants()
22 #self.gc_users()
23 #self.gc_user_tenant_roles()
Tony Mackb61c81c2014-04-21 17:08:12 -040024 self.gc_slivers()
Tony Mackfccb9eb2014-04-14 22:16:42 -040025 #self.gc_sliver_ips()
26 #self.gc_external_routes()
27 pass
Tony Mack387a73f2013-09-18 07:59:14 -040028 except:
29 traceback.print_exc()
30
31 def gc_roles(self):
32 """
33 all role that don't already exist in keystone. Remove keystone roles that
34 don't exist in planetstack
35 """
36 # sync all roles that don't already in keystone
37 keystone_roles = self.driver.shell.keystone.roles.findall()
38 keystone_role_names = [kr.name for kr in keystone_roles]
39 pending_roles = Role.objects.all()
40 pending_role_names = [r.role_type for r in pending_roles]
41 # don't delete roles for now
42 """
43 # delete keystone roles that don't exist in planetstack
44 for keystone_role in keystone_roles:
45 if keystone_role.name == 'admin':
46 continue
47 if keystone_role.name not in pending_role_names:
48 try:
Tony Macka76b8952013-10-05 23:36:30 -040049 self.driver.delete_role({id: keystone_role.id})
Tony Mack387a73f2013-09-18 07:59:14 -040050 except:
51 traceback.print_exc()
52 """
53
54 def gc_tenants(self):
55 """
56 Remove sites and slices that no don't exist in openstack db if they
57 have an enacted time (enacted != None).
58 """
59 # get all sites that where enacted != null. We can assume these sites
60 # have previously been synced and need to be checed for deletion.
61 sites = Site.objects.filter(enacted__isnull=False)
62 site_dict = {}
63 for site in sites:
64 site_dict[site.login_base] = site
65
66 # get all slices that where enacted != null. We can assume these slices
67 # have previously been synced and need to be checed for deletion.
68 slices = Slice.objects.filter(enacted__isnull=False)
69 slice_dict = {}
70 for slice in slices:
71 slice_dict[slice.name] = slice
72
73 # delete keystone tenants that don't have a site record
Tony Macke4be32f2014-03-11 20:45:25 -040074 for deployment in deployment_auth:
75 driver = self.driver.admin_driver(deployment=deployment)
76 tenants = driver.shell.keystone.tenants.findall()
77
78 system_tenants = ['admin','service', 'invisible_to_admin']
79 for tenant in tenants:
80 if tenant.name in system_tenants:
81 continue
82 if tenant.name not in site_dict and tenant.name not in slice_dict:
83 try:
84 driver.delete_tenant(tenant.id)
85 logger.info("deleted tenant: %s" % (tenant))
86 except:
87 logger.log_exc("delete tenant failed: %s" % tenant)
Tony Mack387a73f2013-09-18 07:59:14 -040088
89
90 def gc_users(self):
91 """
Tony Mackf77f1402014-04-02 07:06:53 -040092 Remove users that do not exist in openstack db if they have an
Tony Mack387a73f2013-09-18 07:59:14 -040093 enacted time (enacted != None).
94 """
95 # get all users that where enacted != null. We can assume these users
96 # have previously been synced and need to be checed for deletion.
97 users = User.objects.filter(enacted__isnull=False)
98 user_dict = {}
99 for user in users:
100 user_dict[user.kuser_id] = user
101
102 # delete keystone users that don't have a user record
Tony Mack9b6dde82013-10-06 11:05:49 -0400103 system_users = ['admin', 'nova', 'quantum', 'glance', 'cinder', 'swift', 'service', 'demo']
Tony Macke4be32f2014-03-11 20:45:25 -0400104 for deployment in deployment_auth:
105 driver = self.driver.admin_driver(deployment=deployment)
106 users = driver.shell.keystone.users.findall()
107 for user in users:
108 if user.name in system_users:
109 continue
110 if user.id not in user_dict:
111 try:
112 self.driver.delete_user(user.id)
113 logger.info("deleted user: %s" % user)
114 except:
115 logger.log_exc("delete user failed: %s" % user)
Tony Mack387a73f2013-09-18 07:59:14 -0400116
117
118 def gc_user_tenant_roles(self):
119 """
120 Remove roles that don't exist in openstack db if they have
121 an enacted time (enacted != None).
122 """
123 # get all site privileges and slice memberships that have been enacted
124 user_tenant_roles = defaultdict(list)
125 for site_priv in SitePrivilege.objects.filter(enacted__isnull=False):
126 user_tenant_roles[(site_priv.user.kuser_id, site_priv.site.tenant_id)].append(site_priv.role.role)
Tony Macka76b8952013-10-05 23:36:30 -0400127 for slice_memb in SlicePrivilege.objects.filter(enacted__isnull=False):
Tony Mack387a73f2013-09-18 07:59:14 -0400128 user_tenant_roles[(slice_memb.user.kuser_id, slice_memb.slice.tenant_id)].append(slice_memb.role.role)
129
130 # Some user tenant role aren't stored in planetstack but they must be preserved.
131 # Role that fall in this category are
132 # 1. Never remove a user's role that their home site
133 # 2. Never remove a user's role at a slice they've created.
134 # Keep track of all roles that must be preserved.
135 users = User.objects.all()
Tony Macke4be32f2014-03-11 20:45:25 -0400136 for deployment in deployment_auth:
137 driver = self.driver.admin_driver(deployment=deployment)
138 tenants = driver.shell.keystone.tenants.list()
139 for user in users:
140 # skip admin roles
141 if user.kuser_id == self.driver.admin_user.id:
142 continue
143
144 ignore_tenant_ids = []
145 k_user = driver.shell.keystone.users.find(id=user.kuser_id)
146 ignore_tenant_ids = [s['tenant_id'] for s in user.slices.values()]
147 if user.site:
148 ignore_tenant_ids.append(user.site.tenant_id)
Tony Mack387a73f2013-09-18 07:59:14 -0400149
Tony Macke4be32f2014-03-11 20:45:25 -0400150 # get user roles in keystone
151 for tenant in tenants:
152 # skip preserved tenant ids
153 if tenant.tenant_id in ignore_tenant_ids:
154 continue
155 # compare user tenant roles
156 user_tenant_role_ids = user_tenant_roles.get((user.kuser_id, tenant.id), [])
Tony Mack387a73f2013-09-18 07:59:14 -0400157
Tony Macke4be32f2014-03-11 20:45:25 -0400158 if user_tenant_role_ids:
159 # The user has roles at the tenant. Check if roles need to
160 # be updated.
161 k_user_roles = driver.shell.keystone.roles.roles_for_user(k_user, tenant)
162 for k_user_role in k_user_roles:
163 if k_user_role.role_id not in user_tenant_role_ids:
164 driver.shell.keyston.remove_user_role(k_user, k_user_role, tenant)
165 logger.info("removed user role %s for %s at %s" % \
166 (k_user_role, k_user.username, tenant.name))
167 else:
168 # remove all roles the user has at the tenant.
169 for k_user_role in k_user_roles:
170 driver.shell.keyston.remove_user_role(k_user, k_user_role, tenant)
171 logger.info("removed user role %s for %s at %s" % \
172 (k_user_role, k_user.username, tenant.name))
Tony Mack387a73f2013-09-18 07:59:14 -0400173
174 def gc_slivers(self):
175 """
176 Remove slivers that no don't exist in openstack db if they have
177 an enacted time (enacted != None).
178 """
179 # get all slivers where enacted != null. We can assume these users
180 # have previously been synced and need to be checed for deletion.
181 slivers = Sliver.objects.filter(enacted__isnull=False)
182 sliver_dict = {}
183 for sliver in slivers:
184 sliver_dict[sliver.instance_id] = sliver
185
Tony Macke4be32f2014-03-11 20:45:25 -0400186 for tenant in self.driver.shell.keystone.tenants.list():
Tony Mackb61c81c2014-04-21 17:08:12 -0400187 if tenant.name in ['admin', 'services']:
188 continue
Tony Macke4be32f2014-03-11 20:45:25 -0400189 # delete sliver that don't have a sliver record
190 tenant_driver = self.driver.client_driver(tenant=tenant.name, deployment=sliver.node.deployment)
191 for instance in tenant_driver.nova.servers.list():
192 if instance.uuid not in sliver_dict:
193 try:
194 tenant_driver.destroy_instance(instance.uuid)
195 logger.info("destroyed sliver: %s" % (instance))
196 except:
197 logger.log_exc("destroy sliver failed: %s" % instance)
198
Tony Mack387a73f2013-09-18 07:59:14 -0400199
200 def gc_sliver_ips(self):
201 """
202 Update ips that have changed.
203 """
204 # fill in null ip addresses
205 slivers = Sliver.objects.filter(ip=None)
206 for sliver in slivers:
207 # update connection
Tony Macke4be32f2014-03-11 20:45:25 -0400208
209 driver = self.driver.client_driver(tenant=sliver.slice.name, deployment=sliver.node.deployment)
Tony Macka76b8952013-10-05 23:36:30 -0400210 servers = driver.shell.nova.servers.findall(id=sliver.instance_id)
Tony Mack387a73f2013-09-18 07:59:14 -0400211 if not servers:
212 continue
213 server = servers[0]
214 ips = server.addresses.get(sliver.slice.name, [])
215 if ips and sliver.ip != ips[0]['addr']:
216 sliver.ip = ips[0]['addr']
217 sliver.save()
218 logger.info("updated sliver ip: %s %s" % (sliver, ips[0]))
219
220 def gc_external_routes(self):
221 pass
Tony Macke1509e82013-10-09 12:38:04 -0400222
223 def gc_nodes(self):
224 # collect local nodes
225 nodes = Node.objects.all()
226 nodes_dict = {}
227 for node in nodes:
228 nodes_dict[node.name] = node
229
230 # collect nova nodes:
Tony Macke1509e82013-10-09 12:38:04 -0400231 compute_nodes_dict = {}
Tony Macke4be32f2014-03-11 20:45:25 -0400232 for deployment in deployment_auth:
233 driver = self.driver.admin_driver(deployment=deployment)
234 compute_nodes = driver.nova.hypervisors.list()
235 for compute_node in compute_nodes:
236 compute_nodes_dict[compute_node.hypervisor_hostname] = compute_node
Tony Macke1509e82013-10-09 12:38:04 -0400237
238 # remove old nodes
239 old_node_names = set(nodes_dict.keys()).difference(compute_nodes_dict.keys())
240 Node.objects.filter(name__in=old_node_names).delete()
241
242 def gc_images(self):
Tony Mack46c2d502013-10-09 13:04:28 -0400243 # collect local images
244 images = Image.objects.all()
245 images_dict = {}
246 for image in images:
247 images_dict[image.name] = image
248
249 # collect glance images
Tony Mack46c2d502013-10-09 13:04:28 -0400250 glance_images_dict = {}
Tony Macke4be32f2014-03-11 20:45:25 -0400251 for deployment in deployment_auth:
252 driver = self.driver.admin_driver(deployment=deployment)
253 glance_images = driver.shell.glance.get_images()
254 for glance_image in glance_images:
255 glance_images_dict[glance_image['name']] = glance_image
Tony Mack46c2d502013-10-09 13:04:28 -0400256
257 # remove old images
258 old_image_names = set(images_dict.keys()).difference(glance_images_dict.keys())
259 Image.objects.filter(name__in=old_image_names).delete()