diff --git a/circle/dashboard/views/util.py b/circle/dashboard/views/util.py index ad3235f..c26909b 100644 --- a/circle/dashboard/views/util.py +++ b/circle/dashboard/views/util.py @@ -45,7 +45,7 @@ from django.views.decorators.debug import sensitive_post_parameters from django.views.generic import DetailView, View, DeleteView, FormView from django.views.generic.detail import SingleObjectMixin from keystoneauth1.identity import v3 -from vm.models.instance import TemplateGroupMember, TemplateUserMember +from vm.models.instance import TemplateGroupMember, TemplateUserMember, InstanceTemplate from openstack_auth.utils import fix_auth_url_version from vm.models import Instance @@ -419,6 +419,7 @@ class AclUpdateView(LoginRequiredMixin, View, SingleObjectMixin): from openstack_api import keystone return keystone.group_list(request=self.request, user=self.request.user) + # TODO: extract this to openstack_api def __get_glance_admin_client(self, project_id): from keystoneauth1 import session from glanceclient import Client @@ -433,6 +434,7 @@ class AclUpdateView(LoginRequiredMixin, View, SingleObjectMixin): return Client('2', session=session) + # TODO: extract this to openstack_api def __get_keystone_admin_client(self): from keystoneauth1 import session from keystoneclient.v3 import client @@ -601,6 +603,86 @@ class AclUpdateView(LoginRequiredMixin, View, SingleObjectMixin): return redirect("%s#access" % self.template.get_absolute_url()) +class UpdateSharedTemplates(View): + # TODO: extract these to openstack_api + def __get_glance_admin_client(self): + from keystoneauth1 import session + from glanceclient import Client + + auth = v3.Password( + auth_url=fix_auth_url_version(settings.OPENSTACK_KEYSTONE_URL), + user_id=settings.OPENSTACK_CIRCLE_USERID, + password=settings.OPENSTACK_CIRCLE_PASSWORD, + project_id=self.project_id, + ) + session = session.Session(auth=auth, verify=False) + + return Client('2', session=session) + + # TODO: extract this to openstack_api + def __get_keystone_admin_client(self): + from keystoneauth1 import session + from keystoneclient.v3 import client + + auth = v3.Password( + auth_url=fix_auth_url_version(settings.OPENSTACK_KEYSTONE_URL), + user_id=settings.OPENSTACK_CIRCLE_USERID, + password=settings.OPENSTACK_CIRCLE_PASSWORD, + ) + sess = session.Session(auth=auth, verify=False) + return client.Client(session=sess, interface=settings.OPENSTACK_INTERFACE) + + def __get_templates_of_snapshots(self): + images = openstack_api.glance.image_list_detailed(self.request)[0] # TODO: why nested lists? + snapshot_ids = [ + i.id for i in images if hasattr(i, 'image_location') and i.image_location == 'snapshot' + ] + return InstanceTemplate.objects.filter(image_id__in=snapshot_ids) + + def __list_users_of_group(self, group_id): + keystone = self.__get_keystone_admin_client() + return keystone.users.list(group=group_id) + + def __is_member_of_groups(self, template): + for group in template.groups.all(): + group_members = self.__list_users_of_group(group.group_id) + for group_member in group_members: + if group_member.default_project_id == self.project_id: + return True + return False + + def __cleanup_snapshot(self, template): + try: + template.users.get(project_id=self.project_id) + return # member is assigned as user + except TemplateUserMember.DoesNotExist: + pass + + if not self.__is_member_of_groups(template): + self.glance.image_members.delete(template.image_id, self.project_id) + + def __cleanup_snapshots(self): + templates_of_existing_snaps = self.__get_templates_of_snapshots() + for t in templates_of_existing_snaps: + self.__cleanup_snapshot(t) + + def __update_shared_templates(self): + self.__cleanup_snapshots() + + def post(self, request): + if not hasattr(request.POST, 'secret') or \ + not hasattr(request.POST, 'project_id'): + return HttpResponse(status=400) + + secret = request.POST['secret'] + if secret != settings.SESSIONHOOK_SHARED_SECRET: + return HttpResponse(status=401) + + self.project_id = request.POST['project_id'] + self.glance = self.__get_glance_admin_client() + self.__update_shared_templates() + + class GraphMixin(object): graph_time_options = [ {'time': "1h", 'name': _("1 hour")},