blob: 9e2a37da44adffa904775b8a522d9c84911d7073 [file] [log] [blame]
Sapan Bhatiaf68688d2013-09-03 11:45:46 -04001import os
2import base64
3from planetstack.config import Config
Tony Mack66646d52013-09-24 21:47:12 -04004from observer.openstacksyncstep import OpenStackSyncStep
Sapan Bhatiaf68688d2013-09-03 11:45:46 -04005
Tony Mack66646d52013-09-24 21:47:12 -04006class GarbageCollector(OpenStackSyncStep):
7 requested_interval = 86400
8 provides=[]
Sapan Bhatiaf68688d2013-09-03 11:45:46 -04009
Tony Mack66646d52013-09-24 21:47:12 -040010 def call(self):
Tony Mack387a73f2013-09-18 07:59:14 -040011 try:
12 logger.info('gc start')
13 #self.sync_roles()
14 self.gc_tenants()
15 self.gc_users()
16 self.gc_user_tenant_roles()
17 self.gc_slivers()
18 self.gc_sliver_ips()
19 self.gc_external_routes()
20 except:
21 traceback.print_exc()
22
23 def gc_roles(self):
24 """
25 all role that don't already exist in keystone. Remove keystone roles that
26 don't exist in planetstack
27 """
28 # sync all roles that don't already in keystone
29 keystone_roles = self.driver.shell.keystone.roles.findall()
30 keystone_role_names = [kr.name for kr in keystone_roles]
31 pending_roles = Role.objects.all()
32 pending_role_names = [r.role_type for r in pending_roles]
33 # don't delete roles for now
34 """
35 # delete keystone roles that don't exist in planetstack
36 for keystone_role in keystone_roles:
37 if keystone_role.name == 'admin':
38 continue
39 if keystone_role.name not in pending_role_names:
40 try:
41 self.manager.driver.delete_role({id: keystone_role.id})
42 except:
43 traceback.print_exc()
44 """
45
46 def gc_tenants(self):
47 """
48 Remove sites and slices that no don't exist in openstack db if they
49 have an enacted time (enacted != None).
50 """
51 # get all sites that where enacted != null. We can assume these sites
52 # have previously been synced and need to be checed for deletion.
53 sites = Site.objects.filter(enacted__isnull=False)
54 site_dict = {}
55 for site in sites:
56 site_dict[site.login_base] = site
57
58 # get all slices that where enacted != null. We can assume these slices
59 # have previously been synced and need to be checed for deletion.
60 slices = Slice.objects.filter(enacted__isnull=False)
61 slice_dict = {}
62 for slice in slices:
63 slice_dict[slice.name] = slice
64
65 # delete keystone tenants that don't have a site record
66 tenants = self.driver.shell.keystone.tenants.findall()
67 system_tenants = ['admin','service']
68 for tenant in tenants:
69 if tenant.name in system_tenants:
70 continue
71 if tenant.name not in site_dict and tenant.name not in slice_dict:
72 try:
73 self.driver.delete_tenant(tenant.id)
74 logger.info("deleted tenant: %s" % (tenant))
75 except:
76 logger.log_exc("delete tenant failed: %s" % tenant)
77
78
79 def gc_users(self):
80 """
81 Remove users that no don't exist in openstack db if they have an
82 enacted time (enacted != None).
83 """
84 # get all users that where enacted != null. We can assume these users
85 # have previously been synced and need to be checed for deletion.
86 users = User.objects.filter(enacted__isnull=False)
87 user_dict = {}
88 for user in users:
89 user_dict[user.kuser_id] = user
90
91 # delete keystone users that don't have a user record
92 system_users = ['admin', 'nova', 'quantum', 'glance', 'cinder', 'swift', 'service']
93 users = self.driver.shell.keystone.users.findall()
94 for user in users:
95 if user.name in system_users:
96 continue
97 if user.id not in user_dict:
98 try:
99 #self.manager.driver.delete_user(user.id)
100 logger.info("deleted user: %s" % user)
101 except:
102 logger.log_exc("delete user failed: %s" % user)
103
104
105 def gc_user_tenant_roles(self):
106 """
107 Remove roles that don't exist in openstack db if they have
108 an enacted time (enacted != None).
109 """
110 # get all site privileges and slice memberships that have been enacted
111 user_tenant_roles = defaultdict(list)
112 for site_priv in SitePrivilege.objects.filter(enacted__isnull=False):
113 user_tenant_roles[(site_priv.user.kuser_id, site_priv.site.tenant_id)].append(site_priv.role.role)
114 for slice_memb in SliceMembership.objects.filter(enacted__isnull=False):
115 user_tenant_roles[(slice_memb.user.kuser_id, slice_memb.slice.tenant_id)].append(slice_memb.role.role)
116
117 # Some user tenant role aren't stored in planetstack but they must be preserved.
118 # Role that fall in this category are
119 # 1. Never remove a user's role that their home site
120 # 2. Never remove a user's role at a slice they've created.
121 # Keep track of all roles that must be preserved.
122 users = User.objects.all()
123 preserved_roles = {}
124 for user in users:
125 tenant_ids = [s['tenant_id'] for s in user.slices.values()]
126 tenant_ids.append(user.site.tenant_id)
127 preserved_roles[user.kuser_id] = tenant_ids
128
129
130 # begin removing user tenant roles from keystone. This is stored in the
131 # Metadata table.
132 for metadata in self.driver.shell.keystone_db.get_metadata():
133 # skip admin roles
134 if metadata.user_id == self.manager.driver.admin_user.id:
135 continue
136 # skip preserved tenant ids
137 if metadata.user_id in preserved_roles and \
138 metadata.tenant_id in preserved_roles[metadata.user_id]:
139 continue
140 # get roles for user at this tenant
141 user_tenant_role_ids = user_tenant_roles.get((metadata.user_id, metadata.tenant_id), [])
142
143 if user_tenant_role_ids:
144 # The user has roles at the tenant. Check if roles need to
145 # be updated.
146 user_keystone_role_ids = metadata.data.get('roles', [])
147 for role_id in user_keystone_role_ids:
148 if role_id not in user_tenant_role_ids:
149 user_keystone_role_ids.pop(user_keystone_role_ids.index(role_id))
150 else:
151 # The user has no roles at this tenant.
152 metadata.data['roles'] = []
153 #session.add(metadata)
154 logger.info("pruning metadata for %s at %s" % (metadata.user_id, metadata.tenant_id))
155
156 def gc_slivers(self):
157 """
158 Remove slivers that no don't exist in openstack db if they have
159 an enacted time (enacted != None).
160 """
161 # get all slivers where enacted != null. We can assume these users
162 # have previously been synced and need to be checed for deletion.
163 slivers = Sliver.objects.filter(enacted__isnull=False)
164 sliver_dict = {}
165 for sliver in slivers:
166 sliver_dict[sliver.instance_id] = sliver
167
168 # delete sliver that don't have a sliver record
169 ctx = self.driver.shell.nova_db.ctx
170 instances = self.driver.shell.nova_db.instance_get_all(ctx)
171 for instance in instances:
172 if instance.uuid not in sliver_dict:
173 try:
174 # lookup tenant and update context
175 tenant = self.driver.shell.keystone.tenants.find(id=instance.project_id)
176 driver = self.driver.client_driver(tenant=tenant.name)
177 driver.destroy_instance(instance.uuid)
178 logger.info("destroyed sliver: %s" % (instance))
179 except:
180 logger.log_exc("destroy sliver failed: %s" % instance)
181
182
183 def gc_sliver_ips(self):
184 """
185 Update ips that have changed.
186 """
187 # fill in null ip addresses
188 slivers = Sliver.objects.filter(ip=None)
189 for sliver in slivers:
190 # update connection
191 self.manager.init_admin(tenant=sliver.slice.name)
192 servers = self.manager.driver.shell.nova.servers.findall(id=sliver.instance_id)
193 if not servers:
194 continue
195 server = servers[0]
196 ips = server.addresses.get(sliver.slice.name, [])
197 if ips and sliver.ip != ips[0]['addr']:
198 sliver.ip = ips[0]['addr']
199 sliver.save()
200 logger.info("updated sliver ip: %s %s" % (sliver, ips[0]))
201
202 def gc_external_routes(self):
203 pass