Commit 1e44ca63 by Szabolcs Gelencser

Add initial group assignment

parent cc8d0f7e
...@@ -44,6 +44,7 @@ from django.views.decorators.debug import sensitive_post_parameters ...@@ -44,6 +44,7 @@ from django.views.decorators.debug import sensitive_post_parameters
from django.views.generic import DetailView, View, DeleteView, FormView from django.views.generic import DetailView, View, DeleteView, FormView
from django.views.generic.detail import SingleObjectMixin from django.views.generic.detail import SingleObjectMixin
from keystoneauth1.identity import v3 from keystoneauth1.identity import v3
from vm.models.instance import TemplateGroupMember
from openstack_auth.utils import fix_auth_url_version from openstack_auth.utils import fix_auth_url_version
from vm.models import Instance from vm.models import Instance
...@@ -413,27 +414,9 @@ class RequestFormOperationMixin(FormOperationMixin): ...@@ -413,27 +414,9 @@ class RequestFormOperationMixin(FormOperationMixin):
class AclUpdateView(LoginRequiredMixin, View, SingleObjectMixin): class AclUpdateView(LoginRequiredMixin, View, SingleObjectMixin):
# def send_success_message(self, whom, old_level, new_level): def __get_current_users_groups(self):
# if old_level and new_level:
# msg = _("Acl user/group %(w)s successfully modified.")
# elif not old_level and new_level:
# msg = _("Acl user/group %(w)s successfully added.")
# elif old_level and not new_level:
# msg = _("Acl user/group %(w)s successfully removed.")
# if msg:
# messages.success(self.request, msg % {'w': whom})
#
# def add_levels(self):
# self.request, _('User "%s" has already '
# 'access to this object.') % name)
# self.request, _('Group "%s" has already '
# 'access to this object.') % name)
# self.request, _('User or group "%s" not found.') % name)
def __get_current_users_groups(self, request):
from openstack_api import keystone from openstack_api import keystone
groups = keystone.group_list(request=self.request, user=self.request.user) return keystone.group_list(request=self.request, user=self.request.user)
return [g.name for g in groups]
def __get_glance_admin_client(self, project_id): def __get_glance_admin_client(self, project_id):
from keystoneauth1 import session from keystoneauth1 import session
...@@ -449,7 +432,7 @@ class AclUpdateView(LoginRequiredMixin, View, SingleObjectMixin): ...@@ -449,7 +432,7 @@ class AclUpdateView(LoginRequiredMixin, View, SingleObjectMixin):
return Client('2', session=session) return Client('2', session=session)
def __get_all_projects(self): def __get_keystone_admin_client(self):
from keystoneauth1 import session from keystoneauth1 import session
from keystoneclient.v3 import client from keystoneclient.v3 import client
...@@ -459,9 +442,10 @@ class AclUpdateView(LoginRequiredMixin, View, SingleObjectMixin): ...@@ -459,9 +442,10 @@ class AclUpdateView(LoginRequiredMixin, View, SingleObjectMixin):
password=settings.OPENSTACK_CIRCLE_PASSWORD, password=settings.OPENSTACK_CIRCLE_PASSWORD,
) )
sess = session.Session(auth=auth, verify=False) sess = session.Session(auth=auth, verify=False)
keystone = client.Client(session=sess, interface=settings.OPENSTACK_INTERFACE) return client.Client(session=sess, interface=settings.OPENSTACK_INTERFACE)
return keystone.projects.list( def __get_all_projects(self):
return self.__get_keystone_admin_client().projects.list(
domain=settings.OPENSTACK_CIRCLE_DOMAIN_ID, domain=settings.OPENSTACK_CIRCLE_DOMAIN_ID,
user=settings.OPENSTACK_CIRCLE_USERID user=settings.OPENSTACK_CIRCLE_USERID
) )
...@@ -478,13 +462,35 @@ class AclUpdateView(LoginRequiredMixin, View, SingleObjectMixin): ...@@ -478,13 +462,35 @@ class AclUpdateView(LoginRequiredMixin, View, SingleObjectMixin):
glance = self.__get_glance_admin_client(project_id_of_user) glance = self.__get_glance_admin_client(project_id_of_user)
glance.image_members.update(template.image_id, project_id_of_user, 'accepted') glance.image_members.update(template.image_id, project_id_of_user, 'accepted')
def __handle_group_assignment(self, request): def __list_users_of_group(self, group_id):
keystone = self.__get_keystone_admin_client()
return keystone.users.list(group=group_id)
def __get_group_by_name(self, name):
groups = self.__get_current_users_groups()
for g in groups:
if g.name == name:
return g
return None
def __handle_group_assignment(self):
new_group_name = self.request.POST['name']
template = self.get_object() template = self.get_object()
new_group = self.__get_group_by_name(new_group_name)
old_groups = TemplateGroupMember.objects.filter(
instancetemplate__image_id=template.image_id)
if new_group.id in old_groups:
msg = _("Already shared with group %s" % new_group_name)
messages.warning(self.request, msg)
else:
template.groups.get_or_create(group_id=new_group.id)
template.save()
def __handle_user_assignment(self, request): def __handle_user_assignment(self):
glance = self.__get_glance_admin_client(request.user.tenant_id) glance = self.__get_glance_admin_client(self.request.user.tenant_id)
template = self.get_object() template = self.get_object()
new_template_user = request.POST['name'] new_template_user = self.request.POST['name']
project_id_of_user = self.__get_project_id_by_name(new_template_user) project_id_of_user = self.__get_project_id_by_name(new_template_user)
old_members_generator = glance.image_members.list(template.image_id) old_members_generator = glance.image_members.list(template.image_id)
...@@ -494,31 +500,33 @@ class AclUpdateView(LoginRequiredMixin, View, SingleObjectMixin): ...@@ -494,31 +500,33 @@ class AclUpdateView(LoginRequiredMixin, View, SingleObjectMixin):
msg = _("Template is already shared with %s" % new_template_user) msg = _("Template is already shared with %s" % new_template_user)
messages.warning(self.request, msg) messages.warning(self.request, msg)
elif project_id_of_user is not None: elif project_id_of_user is not None:
membership = glance.image_members.create(template.image_id, project_id_of_user) glance.image_members.create(template.image_id, project_id_of_user)
self.__accept_membership(project_id_of_user) self.__accept_membership(project_id_of_user)
msg = _("Successfully shared with %s" % new_template_user) msg = _("Successfully shared with %s" % new_template_user)
messages.success(self.request, msg) messages.success(self.request, msg)
else: else:
msg = _("User or group with name '%s' doesn't exist" % new_template_user) msg = _("User or group with name '%s' doesn't exist "
"or you are not authorized to share with it" % new_template_user)
messages.error(self.request, msg) messages.error(self.request, msg)
def __handle_assignments(self, request): def __handle_assignments(self):
current_users_groups = self.__get_current_users_groups(request) current_users_groups = self.__get_current_users_groups()
new_template_user = request.POST['name'] current_group_names = [g.name for g in current_users_groups]
new_template_user = self.request.POST['name']
if new_template_user is not None and len(new_template_user) > 0: if new_template_user is not None and len(new_template_user) > 0:
if new_template_user in current_users_groups: if new_template_user in current_group_names:
self.__handle_group_assignment(request) self.__handle_group_assignment()
else: else:
self.__handle_user_assignment(request) self.__handle_user_assignment()
def __get_removes(self, request): def __get_removes(self):
removes = { removes = {
"u": [], "u": [],
"g": [], "g": [],
} }
for key, value in request.POST.items(): for key, value in self.request.POST.items():
m = re.match('remove-([ug])-(.+)', key) m = re.match('remove-([ug])-(.+)', key)
if m: if m:
t, name = m.groups() t, name = m.groups()
...@@ -526,23 +534,23 @@ class AclUpdateView(LoginRequiredMixin, View, SingleObjectMixin): ...@@ -526,23 +534,23 @@ class AclUpdateView(LoginRequiredMixin, View, SingleObjectMixin):
return removes return removes
def __remove_user(self, request, member_id): def __remove_user(self, member_id):
template = self.get_object() template = self.get_object()
glance = self.__get_glance_admin_client(request.user.tenant_id) glance = self.__get_glance_admin_client(self.request.user.tenant_id)
glance.image_members.delete(template.image_id, member_id) glance.image_members.delete(template.image_id, member_id)
def __handle_removes(self, request): def __handle_removes(self):
removes = self.__get_removes(request) removes = self.__get_removes()
for member_id in removes['u']: for member_id in removes['u']:
self.__remove_user(request, member_id) self.__remove_user(member_id)
messages.success(request, _("Successfully removed user")) messages.success(self.request, _("Successfully removed user"))
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
template = self.get_object() template = self.get_object()
openstack_api.glance.image_update(request, template.image_id, visibility="shared") openstack_api.glance.image_update(request, template.image_id, visibility="shared")
self.__handle_assignments(request) self.__handle_assignments()
self.__handle_removes(request) self.__handle_removes()
return redirect("%s#access" % template.get_absolute_url()) return redirect("%s#access" % template.get_absolute_url())
......
...@@ -427,7 +427,7 @@ def user_list(request, project=None, domain=None, group=None, filters=None): ...@@ -427,7 +427,7 @@ def user_list(request, project=None, domain=None, group=None, filters=None):
except keystone_exceptions.NotFound: except keystone_exceptions.NotFound:
raise exceptions.NotFound() raise exceptions.NotFound()
else: else:
users = keystoneclient(request, admin=True).users.list(**kwargs) users = keystoneclient(request).users.list(**kwargs) # TODO: was admin API
return [VERSIONS.upgrade_v2_user(user) for user in users] return [VERSIONS.upgrade_v2_user(user) for user in users]
......
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2018-05-31 12:55
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('vm', '0016_auto_20180522_1515'),
]
operations = [
migrations.CreateModel(
name='TemplateGroupMember',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('group_id', models.CharField(max_length=100, unique=True)),
],
options={
'db_table': 'vm_template_group_member',
},
),
migrations.CreateModel(
name='TemplateUserMember',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('user_id', models.CharField(max_length=100, unique=True)),
],
options={
'db_table': 'vm_template_user_member',
},
),
migrations.AddField(
model_name='instancetemplate',
name='groups',
field=models.ManyToManyField(blank=True, help_text='Shared with groups', to='vm.TemplateGroupMember', verbose_name='groups'),
),
migrations.AddField(
model_name='instancetemplate',
name='users',
field=models.ManyToManyField(blank=True, help_text='Shared with users', to='vm.TemplateUserMember', verbose_name='users'),
),
]
...@@ -119,13 +119,20 @@ class VirtualMachineDescModel(BaseResourceConfigModel): ...@@ -119,13 +119,20 @@ class VirtualMachineDescModel(BaseResourceConfigModel):
abstract = True abstract = True
class TemplateMemberGroup(Model): class TemplateUserMember(Model):
group_id = CharField(blank=False, max_length=100, unique=True) user_id = CharField(blank=False, max_length=100, unique=True)
class Meta: class Meta:
app_label = 'vm' app_label = 'vm'
db_table = 'vm_template_member_group' db_table = 'vm_template_user_member'
class TemplateGroupMember(Model):
group_id = CharField(blank=False, max_length=100, unique=True)
class Meta:
app_label = 'vm'
db_table = 'vm_template_group_member'
class InstanceTemplate(TimeStampedModel): class InstanceTemplate(TimeStampedModel):
...@@ -147,6 +154,20 @@ class InstanceTemplate(TimeStampedModel): ...@@ -147,6 +154,20 @@ class InstanceTemplate(TimeStampedModel):
flavor_id = CharField(blank=False, max_length=100) flavor_id = CharField(blank=False, max_length=100)
owner_id = CharField(blank=False, max_length=100) owner_id = CharField(blank=False, max_length=100)
users = ManyToManyField(
TemplateUserMember,
blank=True,
help_text=_("Shared with users"),
verbose_name=_('users'),
)
groups = ManyToManyField(
TemplateGroupMember,
blank=True,
help_text=_("Shared with groups"),
verbose_name=_('groups'),
)
class Meta: class Meta:
app_label = 'vm' app_label = 'vm'
db_table = 'vm_instancetemplate' db_table = 'vm_instancetemplate'
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment